<?php
require_once __DIR__ . '/../utils/Config.php'; require_once SRC_PATH . '/models/Mission.php'; require_once SRC_PATH . '/classes/Database.php'; require_once SRC_PATH . '/classes/LanguageController.php'; class MissionController { public $db; private $languageController; public function __construct() { $this->db = Database::getInstance(); $this->languageController = LanguageController::getInstance(); } public function getAvailableMissions($currentYear, $currentMonth) { return Mission::getAvailableMissions($this->db, $currentYear, $currentMonth); } public function getMission($id) { return Mission::getById($this->db, $id); } public function startMission($id) { $mission = $this->getMission($id); if (!$mission) { return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.mission_not_found') ]; } if ($mission->getStatus() != Mission::STATUS_NOT_STARTED) { return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.mission_already_started') ]; } $this->db->query( "UPDATE missions SET active = 0 WHERE active = 1" ); $mission->setStatus(Mission::STATUS_IN_PROGRESS); $mission->setActive(true); $mission->save($this->db); $this->db->query( "INSERT INTO mission_progress (mission_id, current_ip, current_directory, trace_level, started_at)
             VALUES (?, ?, ?, ?, ?)", [$mission->getId(), $mission->getTargetIp(), '/', 0, date('Y-m-d H:i:s')] ); $_SESSION['active_mission_id'] = $mission->getId(); return [ 'success' => true, 'message' => $this->languageController->translate('missions_api.mission_started'), 'mission' => $mission->toArray() ]; } public function getActiveMission() { $result = $this->db->query( "SELECT * FROM missions WHERE active = 1 AND status = ?", [Mission::STATUS_IN_PROGRESS] ); $mission = $result->fetch(PDO::FETCH_ASSOC); if ($mission) { return Mission::getById($this->db, $mission['id']); } return null; } public function completeMission($id) { $mission = $this->getMission($id); if (!$mission) { return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.mission_not_found') ]; } if ($mission->getStatus() != Mission::STATUS_IN_PROGRESS) { return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.mission_not_in_progress') ]; } $mission->setStatus(Mission::STATUS_COMPLETED); $mission->setCompletedAt(date('Y-m-d H:i:s')); $mission->save($this->db); $this->db->query( "UPDATE game_state SET credits = credits + ? WHERE id = 1", [$mission->getRewardCredits()] ); if ($mission->getId() === 1) { $_SESSION['first_mission_completed'] = true; } try { $translatedMessage = $this->languageController->translate('missions_api.mission_completed_credits', ['credits' => $mission->getRewardCredits()]); $this->db->query( "INSERT INTO event_log (type, message, event_time) VALUES (?, ?, ?)", ['success', $translatedMessage, date('H:i')] ); if (!isset($_SESSION['pending_events'])) { $_SESSION['pending_events'] = []; } $_SESSION['pending_events'][] = [ 'type' => 'success', 'message' => $translatedMessage, 'event_time' => date('H:i') ]; } catch (Exception $e) { } return [ 'success' => true, 'message' => $this->languageController->translate('missions_api.mission_completed_credits', ['credits' => $mission->getRewardCredits()]), 'credits_reward' => $mission->getRewardCredits() ]; } public function failMission($id) { $mission = $this->getMission($id); if (!$mission) { return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.mission_not_found') ]; } if ($mission->getStatus() != Mission::STATUS_IN_PROGRESS) { return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.mission_not_in_progress') ]; } $mission->setStatus(Mission::STATUS_FAILED); $mission->save($this->db); return [ 'success' => true, 'message' => $this->languageController->translate('missions_api.mission_failed') ]; } public function getFilesystem($missionId, $targetIp, $directory = '/') { if ($directory !== '/') { $actualDir = $this->db->query( "SELECT path FROM mission_filesystem
                 WHERE mission_id = ? AND target_ip = ? AND LOWER(path) = LOWER(?) AND is_directory = 1", [$missionId, $targetIp, $directory] )->fetch(PDO::FETCH_ASSOC); if ($actualDir) { $directory = $actualDir['path']; } } if ($directory !== '/' && !str_ends_with($directory, '/')) { $directory .= '/'; } $result = $this->db->query( "SELECT * FROM mission_filesystem
             WHERE mission_id = ? AND target_ip = ? AND path LIKE ? AND path <> ?
             ORDER BY is_directory DESC, name ASC", [$missionId, $targetIp, $directory . '%', $directory] ); $files = []; while ($file = $result->fetch(PDO::FETCH_ASSOC)) { $relativePath = substr($file['path'], strlen($directory)); if (!strpos($relativePath, '/')) { $files[] = [ 'name' => $file['name'], 'path' => $file['path'], 'is_directory' => $file['is_directory'], 'size' => $file['size'], 'permissions' => $file['permissions'] ]; } } return $files; } public function getFileContent($missionId, $targetIp, $path) { $result = $this->db->query( "SELECT content FROM mission_filesystem
             WHERE mission_id = ? AND target_ip = ? AND LOWER(path) = LOWER(?) AND is_directory = 0", [$missionId, $targetIp, $path] ); $file = $result->fetch(PDO::FETCH_ASSOC); if ($file) { return $file['content']; } $filename = basename($path); $result = $this->db->query( "SELECT content FROM mission_filesystem
             WHERE mission_id = ? AND target_ip = ? AND LOWER(name) = LOWER(?) AND is_directory = 0", [$missionId, $targetIp, $filename] ); $file = $result->fetch(PDO::FETCH_ASSOC); return $file ? $file['content'] : null; } public function deleteFile($missionId, $targetIp, $path) { $file = $this->db->query( "SELECT * FROM mission_filesystem
             WHERE mission_id = ? AND target_ip = ? AND LOWER(path) = LOWER(?) AND is_directory = 0", [$missionId, $targetIp, $path] )->fetch(); if (!$file) { return false; } $this->db->query( "DELETE FROM mission_filesystem
             WHERE mission_id = ? AND target_ip = ? AND LOWER(path) = LOWER(?) AND is_directory = 0", [$missionId, $targetIp, $path] ); return true; } public function getMissionLogs($missionId, $targetIp) { $result = $this->db->query( "SELECT * FROM mission_logs
             WHERE mission_id = ? AND target_ip = ?
             ORDER BY timestamp DESC LIMIT 20", [$missionId, $targetIp] ); return $result->fetchAll(PDO::FETCH_ASSOC); } public function logCommand($missionId, $targetIp, $command, $traceImpact = 1) { $vpnState = $this->db->query( "SELECT vpn_active, vpn_capacity FROM game_state WHERE id = 1" )->fetch(PDO::FETCH_ASSOC); $actualTraceImpact = $traceImpact; $commandCount = $this->db->query( "SELECT COUNT(*) FROM mission_logs WHERE mission_id = ?", [$missionId] )->fetchColumn(); $mission = $this->getMission($missionId); $isEarlyMission = ($mission && $mission->getId() <= 2); $vpnActive = ($vpnState && $vpnState['vpn_active'] == 1 && $vpnState['vpn_capacity'] > 0); if ($isEarlyMission) { $requiredPerTrace = $vpnActive ? 5 : 3; if ($commandCount % $requiredPerTrace !== 0) { $actualTraceImpact = 0; if ($vpnActive) { $this->db->query( "UPDATE game_state SET vpn_capacity = vpn_capacity - ? WHERE id = 1", [$traceImpact] ); $newCapacity = $this->db->query("SELECT vpn_capacity FROM game_state WHERE id = 1")->fetchColumn(); if ($newCapacity <= 0) { $this->db->query("UPDATE game_state SET vpn_active = 0, vpn_capacity = 0 WHERE id = 1"); } } } } else { if ($vpnActive) { if ($commandCount % 2 == 1) { $actualTraceImpact = 0; $this->db->query( "UPDATE game_state SET vpn_capacity = vpn_capacity - ? WHERE id = 1", [$traceImpact] ); $newCapacity = $this->db->query("SELECT vpn_capacity FROM game_state WHERE id = 1")->fetchColumn(); if ($newCapacity <= 0) { $this->db->query("UPDATE game_state SET vpn_active = 0, vpn_capacity = 0 WHERE id = 1"); } } } } $this->db->query( "INSERT INTO mission_logs (mission_id, target_ip, command, trace_impact)
             VALUES (?, ?, ?, ?)", [$missionId, $targetIp, $command, $actualTraceImpact] ); $currentTraceLevel = $this->db->query( "SELECT trace_level FROM mission_progress WHERE mission_id = ?", [$missionId] )->fetchColumn(); $newTraceLevel = min(100, $currentTraceLevel + $actualTraceImpact); $this->db->query( "UPDATE mission_progress SET trace_level = ?
             WHERE mission_id = ?", [$newTraceLevel, $missionId] ); $mission = $this->getMission($missionId); $traceThreshold = $mission->getTraceThreshold(); if ($newTraceLevel >= $traceThreshold && !$this->isTimerStarted($missionId)) { $this->startTimer($missionId); return [ 'success' => true, 'trace_level' => $newTraceLevel, 'timer_started' => true, 'timer_seconds' => $mission->getTraceTimer(), 'vpn_capacity' => $this->db->query("SELECT vpn_capacity FROM game_state WHERE id = 1")->fetchColumn() ]; } return [ 'success' => true, 'trace_level' => $newTraceLevel, 'timer_started' => $this->isTimerStarted($missionId), 'vpn_capacity' => $this->db->query("SELECT vpn_capacity FROM game_state WHERE id = 1")->fetchColumn() ]; } private function isTimerStarted($missionId) { $result = $this->db->query( "SELECT timer_started_at FROM mission_progress WHERE mission_id = ?", [$missionId] ); $progress = $result->fetch(PDO::FETCH_ASSOC); return $progress && $progress['timer_started_at'] !== null; } private function startTimer($missionId) { $this->db->query( "UPDATE mission_progress SET timer_started_at = ? WHERE mission_id = ?", [date('Y-m-d H:i:s'), $missionId] ); } public function checkTimerExpired($missionId) { $mission = $this->getMission($missionId); if (!$mission || $mission->getStatus() != Mission::STATUS_IN_PROGRESS) { return false; } $result = $this->db->query( "SELECT timer_started_at FROM mission_progress WHERE mission_id = ?", [$missionId] ); $progress = $result->fetch(PDO::FETCH_ASSOC); if (!$progress || $progress['timer_started_at'] === null) { return false; } $startTime = strtotime($progress['timer_started_at']); $currentTime = time(); $elapsedSeconds = $currentTime - $startTime; return $elapsedSeconds >= $mission->getTraceTimer(); } public function updateCurrentDirectory($missionId, $directory) { $this->db->query( "UPDATE mission_progress SET current_directory = ? WHERE mission_id = ?", [$directory, $missionId] ); } public function updateCurrentIp($missionId, $ip) { $this->db->query( "UPDATE mission_progress SET current_ip = ?, current_directory = '/' WHERE mission_id = ?", [$ip, $missionId] ); } public function getMissionProgress($missionId) { $result = $this->db->query( "SELECT * FROM mission_progress WHERE mission_id = ?", [$missionId] ); return $result->fetch(PDO::FETCH_ASSOC); } public function addMissionMessage($mission, $anonChat) { $sender = $this->getRandomSender(); $title = "Mission: " . $mission->getTitle(); $message = $mission->getDescription(); $metadata = json_encode([ 'mission_id' => $mission->getId(), 'type' => 'mission' ]); return $anonChat->addMessage( $title, $message, 'date', null, $mission->getYearAvailable(), $mission->getMonthAvailable(), 'inbox', $metadata ); } private function getRandomSender() { $senders = [ 'ShadowHawk', 'ZeroCool', 'PhantomByte', 'NeoMatrix', 'CipherGhost', 'Anon1337', 'DarkCode', 'CyberWolf', 'BitRebel', 'HexHunter' ]; return $senders[array_rand($senders)]; } public function updateMissionAvailability($currentYear, $currentMonth) { $result = $this->db->query( "UPDATE missions
             SET is_available = 1
             WHERE is_available = 0
             AND status = ?
             AND ((year_available < ?) OR (year_available = ? AND month_available <= ?))", [Mission::STATUS_NOT_STARTED, $currentYear, $currentYear, $currentMonth] ); $updatedCount = $result->rowCount(); if ($updatedCount > 0) { } return $updatedCount; } public function validateObjective($mission, $actionType, $actionData) { $objective = $mission->getCompletionObjective(); $objectiveType = explode(':', $objective)[0]; switch($objectiveType) { case 'find_file': return $this->validateFindFile($mission, $actionData); case 'decrypt_file': return $this->validateDecryptFile($mission, $actionData); case 'delete_file': return $this->validateDeleteFile($mission, $actionData); case 'delete_multiple': return $this->validateDeleteMultiple($mission, $actionData); case 'steal_data': return $this->validateStealData($mission, $actionData); case 'plant_backdoor': return $this->validatePlantBackdoor($mission, $actionData); case 'modify_file': return $this->validateModifyFile($mission, $actionData); case 'modify_content': return $this->validateModifyContent($mission, $actionData); case 'copy_file': return $this->validateCopyFile($mission, $actionData); case 'chain_access': return $this->validateChainAccess($mission, $actionData); case 'collect_emails': return $this->validateCollectEmails($mission, $actionData); case 'extract_credentials': return $this->validateExtractCredentials($mission, $actionData); case 'corrupt_logs': return $this->validateCorruptLogs($mission, $actionData); case 'replace_file': return $this->validateReplaceFile($mission, $actionData); case 'chain_steal': return $this->validateChainSteal($mission, $actionData); case 'stealth_operation': return $this->validateStealthOperation($mission, $actionData); case 'ping_targets': return $this->validatePingTargets($mission, $actionData); default: return [ 'success' => false, 'message' => $this->languageController->translate('missions_api.unknown_objective_type', ['type' => $objectiveType]) ]; } } private function validateFindFile($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetFile = substr($objective, 10); $filePath = $actionData['file_path'] ?? ''; if (strcasecmp(basename($filePath), $targetFile) === 0) { $this->completeMission($mission->getId()); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $this->languageController->translate('missions_api.file_copied_successfully') ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => $this->languageController->translate('missions_api.file_copied_successfully') ]; } private function validateDecryptFile($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetFile = substr($objective, 13); $filePath = $actionData['file_path'] ?? ''; if (str_ends_with($filePath, '.enc') || str_ends_with($filePath, '.aes') || str_ends_with($filePath, '.pgp')) { return [ 'success' => true, 'objective_completed' => false, 'message' => $this->languageController->translate('missions_api.decrypt_first') ]; } $targetBaseName = pathinfo($targetFile, PATHINFO_FILENAME); $copiedBaseName = pathinfo(basename($filePath), PATHINFO_FILENAME); if ($copiedBaseName === $targetBaseName) { $this->completeMission($mission->getId()); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $this->languageController->translate('missions_api.file_copied_successfully') ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => $this->languageController->translate('missions_api.file_copied') ]; } private function validateDeleteFile($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetFile = substr($objective, 12); $filePath = $actionData['file_path'] ?? ''; if (strcasecmp(basename($filePath), $targetFile) === 0) { $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_deleted') ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_deleted') ]; } private function validateDeleteMultiple($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetFiles = substr($objective, 16); $requiredFiles = array_map('trim', explode(',', $targetFiles)); $filePath = $actionData['file_path'] ?? ''; $sessionKey = "mission_{$mission->getId()}_deleted_files"; if (!isset($_SESSION[$sessionKey])) { $_SESSION[$sessionKey] = []; } $matchedFile = null; foreach ($requiredFiles as $requiredFile) { if (strcasecmp($filePath, $requiredFile) === 0) { $matchedFile = $requiredFile; break; } } if ($matchedFile && !in_array($matchedFile, $_SESSION[$sessionKey])) { $_SESSION[$sessionKey][] = $matchedFile; } elseif ($matchedFile) { } else { } if (count($_SESSION[$sessionKey]) >= count($requiredFiles)) { unset($_SESSION[$sessionKey]); $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_deleted') ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_deleted') ]; } private function validateStealData($mission, $actionData) { $objective = $mission->getCompletionObjective(); $requiredCount = (int)substr($objective, 11); $filePath = $actionData['file_path'] ?? ''; $requiredFiles = []; if ($mission->getId() == 4) { $requiredFiles = [ 'breaking_news.txt', 'confidential_sources.txt', 'whistleblower_docs.pdf' ]; } elseif ($mission->getId() == 13) { $requiredFiles = [ 'employees.db', 'financial_records.xls' ]; } $sessionKey = "mission_{$mission->getId()}_stolen_files"; if (!isset($_SESSION[$sessionKey])) { $_SESSION[$sessionKey] = []; } $fileName = basename($filePath); if (!empty($requiredFiles)) { $languageController = LanguageController::getInstance(); if (!in_array($fileName, $requiredFiles)) { return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } if (in_array($fileName, $_SESSION[$sessionKey])) { return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } $_SESSION[$sessionKey][] = $fileName; $stolenCount = count($_SESSION[$sessionKey]); if ($stolenCount >= $requiredCount) { $this->completeMission($mission->getId()); unset($_SESSION[$sessionKey]); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_copied') ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } if (!in_array($filePath, $_SESSION[$sessionKey])) { $_SESSION[$sessionKey][] = $filePath; } $stolenCount = count($_SESSION[$sessionKey]); $languageController = LanguageController::getInstance(); if ($stolenCount >= $requiredCount) { $this->completeMission($mission->getId()); unset($_SESSION[$sessionKey]); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_copied') ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } private function validatePlantBackdoor($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', substr($objective, 15), 2); $targetPath = $parts[0]; $requiredPassword = $parts[1] ?? null; $filePath = $actionData['file_path'] ?? ''; $providedPassword = $actionData['password'] ?? null; if (strcasecmp($filePath, $targetPath) !== 0) { $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.backdoor_wrong_location') ]; } if ($requiredPassword !== null) { $languageController = LanguageController::getInstance(); if ($providedPassword === null) { return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.access_denied_modification_code') ]; } if ($providedPassword !== $requiredPassword) { return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.access_denied_invalid_code') ]; } } $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.backdoor_planted_success') ]; } private function validateModifyFile($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', substr($objective, 12)); $targetPath = $parts[0]; $requiredPassword = $parts[1] ?? null; $blockingFiles = $parts[2] ?? null; $filePath = $actionData['file_path'] ?? ''; $providedPassword = $actionData['password'] ?? null; if (strcasecmp($filePath, $targetPath) !== 0) { $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_modified_wrong_target') ]; } if ($blockingFiles !== null) { $blockingFileList = explode(',', $blockingFiles); $stillExistingFiles = []; foreach ($blockingFileList as $blockingFile) { $blockingFile = trim($blockingFile); $secondaryIp = $mission->getSecondaryIp(); $ips = [$mission->getTargetIp()]; if ($secondaryIp) { $ips = array_merge($ips, explode(',', $secondaryIp)); } foreach ($ips as $ip) { $ip = trim($ip); $fileExists = $this->checkFileExists($mission->getId(), $ip, $blockingFile); if ($fileExists) { $stillExistingFiles[] = $blockingFile; break; } } } if (count($stillExistingFiles) > 0) { $languageController = LanguageController::getInstance(); return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.access_denied_security_tools', ['files' => implode(', ', $stillExistingFiles)]) ]; } } if ($requiredPassword !== null) { $languageController = LanguageController::getInstance(); if ($providedPassword === null) { return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.access_denied_admin_password') ]; } if ($providedPassword !== $requiredPassword) { return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.access_denied_invalid_password') ]; } } $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_modified_success') ]; } private function validateModifyContent($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', $objective); if (count($parts) < 4) { $languageController = LanguageController::getInstance(); return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.invalid_objective_format') ]; } $targetFile = $parts[1]; if (!isset($actionData['file']) || $actionData['file'] !== $targetFile) { $languageController = LanguageController::getInstance(); return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.wrong_file_target', ['target' => $targetFile]) ]; } $missionId = $mission->getId(); $progress = $this->db->query( "SELECT current_ip FROM mission_progress WHERE mission_id = ?", [$missionId] )->fetch(); if (!$progress) { $languageController = LanguageController::getInstance(); return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.mission_not_found') ]; } $currentIp = $progress['current_ip']; $modifiedContent = $this->getFileContent($missionId, $currentIp, $targetFile); if (!$modifiedContent) { $languageController = LanguageController::getInstance(); return [ 'success' => false, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_not_found_empty') ]; } $modificationsStr = implode(':', array_slice($parts, 2)); $modificationPairs = explode('|', $modificationsStr); $sessionKey = "mission_{$missionId}_modifications"; if (!isset($_SESSION[$sessionKey])) { $_SESSION[$sessionKey] = []; } $totalModifications = count($modificationPairs); $completedCount = 0; foreach ($modificationPairs as $pair) { $pairParts = explode(':', $pair); if (count($pairParts) != 2) continue; $oldValue = trim($pairParts[0]); $newValue = trim($pairParts[1]); if (in_array($oldValue, $_SESSION[$sessionKey])) { $completedCount++; continue; } if (strpos($modifiedContent, $oldValue) === false && strpos($modifiedContent, $newValue) !== false) { $_SESSION[$sessionKey][] = $oldValue; $completedCount++; } } if ($completedCount >= $totalModifications) { $this->completeMission($mission->getId()); unset($_SESSION[$sessionKey]); } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => ($completedCount >= $totalModifications), 'mission_completed' => ($completedCount >= $totalModifications), 'message' => $languageController->translate('missions_api.file_content_modified_success') ]; } private function validateCopyFile($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', $objective); if (count($parts) < 3) { $languageController = LanguageController::getInstance(); return [ 'success' => true, 'message' => $languageController->translate('missions_api.invalid_objective_format') ]; } $requiredFiles = explode(',', $parts[1]); $missionId = $mission->getId(); $copiedFiles = $this->getCopiedFiles($missionId); $allCopied = true; foreach ($requiredFiles as $requiredFile) { $requiredFile = trim($requiredFile); $found = false; foreach ($copiedFiles as $copiedFile) { if (basename($copiedFile) === basename($requiredFile)) { $found = true; break; } } if (!$found) { $allCopied = false; break; } } if (!$allCopied) { $languageController = LanguageController::getInstance(); return [ 'success' => true, 'message' => $languageController->translate('missions_api.file_copied') ]; } $this->completeMission($missionId); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.all_files_extracted') ]; } public function addCopiedFile($missionId, $filePath) { $result = $this->db->query( "SELECT copied_files FROM mission_progress WHERE mission_id = ?", [$missionId] )->fetch(); $copiedFiles = $result['copied_files'] ?? ''; $filesArray = $copiedFiles ? explode(',', $copiedFiles) : []; if (!in_array($filePath, $filesArray)) { $filesArray[] = $filePath; $newCopiedFiles = implode(',', $filesArray); $this->db->query( "UPDATE mission_progress SET copied_files = ? WHERE mission_id = ?", [$newCopiedFiles, $missionId] ); } } public function getCopiedFiles($missionId) { $result = $this->db->query( "SELECT copied_files FROM mission_progress WHERE mission_id = ?", [$missionId] )->fetch(); $copiedFiles = $result['copied_files'] ?? ''; return $copiedFiles ? explode(',', $copiedFiles) : []; } private function checkFileExists($missionId, $targetIp, $filePath) { $db = Database::getInstance(); $missionId = (int)$missionId; $targetIp = str_replace("'", "''", $targetIp); $filePath = str_replace("'", "''", $filePath); $result = $db->query("
            SELECT COUNT(*) as count
            FROM mission_filesystem
            WHERE mission_id = $missionId
            AND target_ip = '$targetIp'
            AND (
                LOWER(path) = LOWER('$filePath')
                OR LOWER(path || '/' || name) = LOWER('$filePath')
            )
            AND is_directory = 0
        "); $row = $result->fetch(PDO::FETCH_ASSOC); return $row['count'] > 0; } private function validateChainAccess($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetIps = explode(',', substr($objective, 13)); $accessedIps = $actionData['accessed_ips'] ?? []; $allAccessed = true; foreach ($targetIps as $ip) { if (!in_array(trim($ip), $accessedIps)) { $allAccessed = false; break; } } if ($allAccessed) { $this->completeMission($mission->getId()); $sessionKey = 'mission_' . $mission->getId() . '_accessed_ips'; unset($_SESSION[$sessionKey]); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.all_systems_accessed') ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.systems_accessed', ['current' => count($accessedIps), 'total' => count($targetIps)]) ]; } private function validateCollectEmails($mission, $actionData) { $objective = $mission->getCompletionObjective(); $requiredCount = (int)substr($objective, 15); $filePath = $actionData['file_path'] ?? ''; $requiredFiles = []; if ($mission->getId() == 15) { $requiredFiles = [ 'earnings_fraud.eml', 'bribery_scheme.eml', 'environmental_coverup.eml' ]; } $sessionKey = "mission_{$mission->getId()}_collected_emails"; if (!isset($_SESSION[$sessionKey])) { $_SESSION[$sessionKey] = []; } $fileName = basename($filePath); if (!empty($requiredFiles)) { $languageController = LanguageController::getInstance(); if (!in_array($fileName, $requiredFiles)) { return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } if (in_array($fileName, $_SESSION[$sessionKey])) { return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } $_SESSION[$sessionKey][] = $fileName; $collectedCount = count($_SESSION[$sessionKey]); if ($collectedCount >= $requiredCount) { $this->completeMission($mission->getId()); unset($_SESSION[$sessionKey]); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_copied') ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } if (!in_array($filePath, $_SESSION[$sessionKey])) { $_SESSION[$sessionKey][] = $filePath; } $collectedCount = count($_SESSION[$sessionKey]); $languageController = LanguageController::getInstance(); if ($collectedCount >= $requiredCount) { $this->completeMission($mission->getId()); unset($_SESSION[$sessionKey]); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_copied') ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_copied') ]; } private function validateExtractCredentials($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetUser = substr($objective, 19); $extractedUser = $actionData['extracted_user'] ?? ''; $hasCredentials = $actionData['has_credentials'] ?? false; if ($extractedUser === $targetUser && $hasCredentials) { $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.credentials_extracted', ['user' => $targetUser]) ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $hasCredentials ? $languageController->translate('missions_api.wrong_user_credentials') : $languageController->translate('missions_api.no_credentials_found') ]; } private function validateCorruptLogs($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', $objective); $requiredCount = (int)$parts[1]; $filePath = $actionData['file_path'] ?? ''; $sessionKey = "mission_{$mission->getId()}_corrupted_files"; if (!isset($_SESSION[$sessionKey])) { $_SESSION[$sessionKey] = []; } if (in_array($filePath, $_SESSION[$sessionKey])) { $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_already_corrupted') ]; } $_SESSION[$sessionKey][] = $filePath; $corruptedCount = count($_SESSION[$sessionKey]); if ($corruptedCount >= $requiredCount) { $this->completeMission($mission->getId()); unset($_SESSION[$sessionKey]); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.all_logs_corrupted') ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.file_corrupted_progress', ['current' => $corruptedCount, 'total' => $requiredCount]) ]; } private function validateReplaceFile($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetFile = substr($objective, 13); $replacedFile = $actionData['replaced_file'] ?? ''; if (basename($replacedFile) === basename($targetFile) || $replacedFile === $targetFile) { $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.file_replaced_success', ['file' => $targetFile]) ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.wrong_file_replaced') ]; } private function validateChainSteal($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', substr($objective, 11)); $requiredSystems = (int)$parts[0]; $filesPerSystem = (int)$parts[1]; $systemsData = $actionData['systems_stolen'] ?? []; $completedSystems = 0; foreach ($systemsData as $system => $fileCount) { if ($fileCount >= $filesPerSystem) { $completedSystems++; } } if ($completedSystems >= $requiredSystems) { $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.chain_steal_complete', ['files' => $filesPerSystem, 'systems' => $requiredSystems]) ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.chain_steal_progress', ['current' => $completedSystems, 'total' => $requiredSystems]) ]; } private function validateStealthOperation($mission, $actionData) { $objective = $mission->getCompletionObjective(); $parts = explode(':', substr($objective, 18)); $innerObjective = $parts[0]; $innerTarget = $parts[1]; $requiredCount = (int)$parts[2]; $maxTrace = (int)$parts[3]; $currentTrace = $actionData['trace_level'] ?? 0; $stolenFiles = $actionData['stolen_files'] ?? []; if ($currentTrace > $maxTrace) { $languageController = LanguageController::getInstance(); return [ 'success' => false, 'objective_completed' => false, 'mission_failed' => true, 'message' => $languageController->translate('missions_api.stealth_failed_trace', ['current' => $currentTrace, 'max' => $maxTrace]) ]; } if (count($stolenFiles) >= $requiredCount && $currentTrace <= $maxTrace) { $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'message' => $languageController->translate('missions_api.stealth_operation_success', ['trace' => $currentTrace]) ]; } return [ 'success' => true, 'objective_completed' => false, 'message' => "Files: " . count($stolenFiles) . "/{$requiredCount}, Trace: {$currentTrace}%/{$maxTrace}%" ]; } private function validatePingTargets($mission, $actionData) { $objective = $mission->getCompletionObjective(); $targetList = substr($objective, 13); $requiredTargets = array_map('trim', explode(',', $targetList)); $pingedTargets = $actionData['pinged_targets'] ?? []; $allPinged = true; foreach ($requiredTargets as $targetIp) { if (!in_array($targetIp, $pingedTargets)) { $allPinged = false; break; } } if ($allPinged) { $this->completeMission($mission->getId()); $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => true, 'mission_completed' => true, 'credits_reward' => $mission->getRewardCredits(), 'message' => $languageController->translate('missions_api.all_targets_verified') ]; } $languageController = LanguageController::getInstance(); return [ 'success' => true, 'objective_completed' => false, 'message' => $languageController->translate('missions_api.targets_pinged_progress', ['current' => count($pingedTargets), 'total' => count($requiredTargets)]) ]; } } 