$dir, 'created' => date('Y-m-d H:i', filectime($wsPath)), 'modified' => date('Y-m-d H:i', filemtime($wsPath)), 'size' => getDirectorySize($wsPath) ]; } } } echo json_encode(['workspaces' => $workspaces]); exit; } if ($action === 'view') { header('Content-Type: application/json'); $name = preg_replace('/[^a-zA-Z0-9\-\_\.]/', '', $_GET['name'] ?? ''); if (empty($name)) { echo json_encode(['error' => 'Invalid workspace name']); exit; } $wsPath = WORKSPACE_DIR . '/' . $name; if (!is_dir($wsPath)) { echo json_encode(['error' => 'Workspace not found']); exit; } // Check for sniper-report.html first $reportPath = $wsPath . '/sniper-report.html'; if (file_exists($reportPath)) { echo json_encode(['reportUrl' => '/loot/workspace/' . urlencode($name) . '/sniper-report.html']); } else { // Use our custom report viewer echo json_encode(['reportUrl' => 'report.php?name=' . urlencode($name)]); } exit; } if ($action === 'download') { $name = preg_replace('/[^a-zA-Z0-9\-\_\.]/', '', $_GET['name'] ?? ''); if (empty($name)) { die('Invalid workspace name'); } $exportFile = EXPORT_DIR . '/' . $name . '.tar.gz'; if (file_exists($exportFile)) { header('Content-Type: application/gzip'); header('Content-Disposition: attachment; filename="' . $name . '.tar.gz"'); header('Content-Length: ' . filesize($exportFile)); readfile($exportFile); exit; } else { die('Export file not found. Please export the workspace first.'); } } } // Handle POST requests (delete, export) if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Content-Type: application/json'); $data = json_decode(file_get_contents('php://input'), true); $action = $data['action'] ?? ''; $name = preg_replace('/[^a-zA-Z0-9\-\_\.]/', '', $data['name'] ?? ''); if (empty($name)) { echo json_encode(['success' => false, 'error' => 'Invalid workspace name']); exit; } $wsPath = WORKSPACE_DIR . '/' . $name; if ($action === 'delete') { if (is_dir($wsPath)) { // Debug info $currentUser = trim(shell_exec('whoami')); // Delete directory recursively using sudo $cmd = "sudo rm -rf " . escapeshellarg($wsPath) . " 2>&1"; exec($cmd, $output, $returnVar); if (!file_exists($wsPath)) { echo json_encode([ 'success' => true, 'message' => 'Workspace deleted', 'debug' => [ 'user' => $currentUser, 'cmd' => $cmd, 'output' => implode("\n", $output), 'return' => $returnVar ] ]); } else { echo json_encode([ 'success' => false, 'error' => 'Failed to delete workspace.', 'debug' => [ 'user' => $currentUser, 'cmd' => $cmd, 'output' => implode("\n", $output), 'return' => $returnVar, 'permissions' => substr(sprintf('%o', fileperms($wsPath)), -4), 'owner' => posix_getpwuid(fileowner($wsPath))['name'] ] ]); } } else { echo json_encode(['success' => false, 'error' => 'Workspace not found']); } exit; } } echo json_encode(['error' => 'Invalid request']); // Helper functions function getDirectorySize($dir) { $size = 0; foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)) as $file) { $size += $file->getSize(); } return formatBytes($size); } function formatBytes($bytes) { if ($bytes >= 1073741824) { return number_format($bytes / 1073741824, 2) . ' GB'; } elseif ($bytes >= 1048576) { return number_format($bytes / 1048576, 2) . ' MB'; } elseif ($bytes >= 1024) { return number_format($bytes / 1024, 2) . ' KB'; } else { return $bytes . ' B'; } }