mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2026-02-04 09:30:30 -07:00
Additional Changes to VPN Tunneling
This commit is contained in:
@@ -75,7 +75,7 @@ const SECTION_HEIGHTS = {
|
||||
};
|
||||
|
||||
const buildVpnGroups = (shellPort) => {
|
||||
const normalizedShell = Number(shellPort) || 47001;
|
||||
const normalizedShell = Number(shellPort) || 47002;
|
||||
return [
|
||||
{
|
||||
key: "shell",
|
||||
@@ -335,7 +335,7 @@ export default function DeviceDetails({ device, onBack, onQuickJobLaunch, onPage
|
||||
const [vpnToggles, setVpnToggles] = useState({});
|
||||
const [vpnCustomPorts, setVpnCustomPorts] = useState([]);
|
||||
const [vpnDefaultPorts, setVpnDefaultPorts] = useState([]);
|
||||
const [vpnShellPort, setVpnShellPort] = useState(47001);
|
||||
const [vpnShellPort, setVpnShellPort] = useState(47002);
|
||||
const [vpnLoadedFor, setVpnLoadedFor] = useState("");
|
||||
// Snapshotted status for the lifetime of this page
|
||||
const [lockedStatus, setLockedStatus] = useState(() => {
|
||||
@@ -347,6 +347,31 @@ export default function DeviceDetails({ device, onBack, onQuickJobLaunch, onPage
|
||||
const now = Date.now() / 1000;
|
||||
return now - tsSec <= 300 ? "Online" : "Offline";
|
||||
});
|
||||
const summary = details.summary || {};
|
||||
const vpnAgentId = useMemo(() => {
|
||||
return (
|
||||
meta.agentId ||
|
||||
summary.agent_id ||
|
||||
agent?.agent_id ||
|
||||
agent?.id ||
|
||||
device?.agent_id ||
|
||||
device?.agent_guid ||
|
||||
device?.id ||
|
||||
""
|
||||
);
|
||||
}, [agent?.agent_id, agent?.id, device?.agent_guid, device?.agent_id, device?.id, meta.agentId, summary.agent_id]);
|
||||
const vpnPortGroups = useMemo(() => buildVpnGroups(vpnShellPort), [vpnShellPort]);
|
||||
const tunnelDevice = useMemo(
|
||||
() => ({
|
||||
...(device || {}),
|
||||
...(agent || {}),
|
||||
summary,
|
||||
hostname: meta.hostname || summary.hostname || device?.hostname || agent?.hostname,
|
||||
agent_id: meta.agentId || summary.agent_id || agent?.agent_id || agent?.id || device?.agent_id || device?.agent_guid,
|
||||
agent_guid: meta.agentGuid || summary.agent_guid || device?.agent_guid || device?.guid || agent?.agent_guid || agent?.guid,
|
||||
}),
|
||||
[agent, device, meta.agentGuid, meta.agentId, meta.hostname, summary]
|
||||
);
|
||||
const quickJobTargets = useMemo(() => {
|
||||
const values = [];
|
||||
const push = (value) => {
|
||||
@@ -715,7 +740,7 @@ export default function DeviceDetails({ device, onBack, onQuickJobLaunch, onPage
|
||||
const numericDefaults = normalizedDefaults
|
||||
.map((p) => Number(p))
|
||||
.filter((p) => Number.isFinite(p) && p > 0);
|
||||
const effectiveShell = Number(shellPort) || 47001;
|
||||
const effectiveShell = Number(shellPort) || 47002;
|
||||
const groups = buildVpnGroups(effectiveShell);
|
||||
const knownPorts = new Set(groups.flatMap((group) => group.ports));
|
||||
const allowedSet = new Set(numericPorts);
|
||||
@@ -887,31 +912,6 @@ export default function DeviceDetails({ device, onBack, onQuickJobLaunch, onPage
|
||||
[]
|
||||
);
|
||||
|
||||
const summary = details.summary || {};
|
||||
const vpnAgentId = useMemo(() => {
|
||||
return (
|
||||
meta.agentId ||
|
||||
summary.agent_id ||
|
||||
agent?.agent_id ||
|
||||
agent?.id ||
|
||||
device?.agent_id ||
|
||||
device?.agent_guid ||
|
||||
device?.id ||
|
||||
""
|
||||
);
|
||||
}, [agent?.agent_id, agent?.id, device?.agent_guid, device?.agent_id, device?.id, meta.agentId, summary.agent_id]);
|
||||
const vpnPortGroups = useMemo(() => buildVpnGroups(vpnShellPort), [vpnShellPort]);
|
||||
const tunnelDevice = useMemo(
|
||||
() => ({
|
||||
...(device || {}),
|
||||
...(agent || {}),
|
||||
summary,
|
||||
hostname: meta.hostname || summary.hostname || device?.hostname || agent?.hostname,
|
||||
agent_id: meta.agentId || summary.agent_id || agent?.agent_id || agent?.id || device?.agent_id || device?.agent_guid,
|
||||
agent_guid: meta.agentGuid || summary.agent_guid || device?.agent_guid || device?.guid || agent?.agent_guid || agent?.guid,
|
||||
}),
|
||||
[agent, device, meta.agentGuid, meta.agentId, meta.hostname, summary]
|
||||
);
|
||||
// Build a best-effort CPU display from summary fields
|
||||
const cpuInfo = useMemo(() => {
|
||||
const cpu = details.cpu || summary.cpu || {};
|
||||
|
||||
@@ -93,6 +93,8 @@ export default function ReverseTunnelPowershell({ device }) {
|
||||
const socketRef = useRef(null);
|
||||
const localSocketRef = useRef(false);
|
||||
const terminalRef = useRef(null);
|
||||
const agentIdRef = useRef("");
|
||||
const tunnelIdRef = useRef("");
|
||||
|
||||
const agentId = useMemo(() => {
|
||||
return (
|
||||
@@ -107,6 +109,14 @@ export default function ReverseTunnelPowershell({ device }) {
|
||||
);
|
||||
}, [device]);
|
||||
|
||||
useEffect(() => {
|
||||
agentIdRef.current = agentId;
|
||||
}, [agentId]);
|
||||
|
||||
useEffect(() => {
|
||||
tunnelIdRef.current = tunnel?.tunnel_id || "";
|
||||
}, [tunnel?.tunnel_id]);
|
||||
|
||||
const ensureSocket = useCallback(() => {
|
||||
if (socketRef.current) return socketRef.current;
|
||||
const existing = typeof window !== "undefined" ? window.BorealisSocket : null;
|
||||
@@ -142,21 +152,20 @@ export default function ReverseTunnelPowershell({ device }) {
|
||||
scrollToBottom();
|
||||
}, [output, scrollToBottom]);
|
||||
|
||||
const stopTunnel = useCallback(
|
||||
async (reason = "operator_disconnect") => {
|
||||
if (!agentId) return;
|
||||
try {
|
||||
await fetch("/api/tunnel/disconnect", {
|
||||
method: "DELETE",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ agent_id: agentId, tunnel_id: tunnel?.tunnel_id, reason }),
|
||||
});
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
},
|
||||
[agentId, tunnel?.tunnel_id]
|
||||
);
|
||||
const stopTunnel = useCallback(async (reason = "operator_disconnect") => {
|
||||
const currentAgentId = agentIdRef.current;
|
||||
if (!currentAgentId) return;
|
||||
const currentTunnelId = tunnelIdRef.current;
|
||||
try {
|
||||
await fetch("/api/tunnel/disconnect", {
|
||||
method: "DELETE",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ agent_id: currentAgentId, tunnel_id: currentTunnelId, reason }),
|
||||
});
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
}, []);
|
||||
|
||||
const closeShell = useCallback(async () => {
|
||||
const socket = ensureSocket();
|
||||
@@ -232,7 +241,10 @@ export default function ReverseTunnelPowershell({ device }) {
|
||||
body: JSON.stringify({ agent_id: agentId }),
|
||||
});
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
if (!resp.ok) throw new Error(data?.error || `HTTP ${resp.status}`);
|
||||
if (!resp.ok) {
|
||||
const detail = data?.detail ? `: ${data.detail}` : "";
|
||||
throw new Error(`${data?.error || `HTTP ${resp.status}`}${detail}`);
|
||||
}
|
||||
const statusResp = await fetch(
|
||||
`/api/tunnel/connect/status?agent_id=${encodeURIComponent(agentId)}&bump=1`
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user