v1.10.0 #471

Merged
LukeGus merged 106 commits from dev-1.10.0 into main 2026-01-01 04:20:12 +00:00
2 changed files with 52 additions and 52 deletions
Showing only changes of commit 731744d6c2 - Show all commits

View File

@@ -137,10 +137,14 @@ async function createJumpHostChain(
const clients: Client[] = []; const clients: Client[] = [];
try { try {
for (let i = 0; i < jumpHosts.length; i++) { // Fetch all jump host configurations in parallel
const jumpHostConfig = await resolveJumpHost(jumpHosts[i].hostId, userId); const jumpHostConfigs = await Promise.all(
jumpHosts.map((jh) => resolveJumpHost(jh.hostId, userId)),
);
if (!jumpHostConfig) { // Validate all configs resolved
for (let i = 0; i < jumpHostConfigs.length; i++) {
if (!jumpHostConfigs[i]) {
sshLogger.error(`Jump host ${i + 1} not found`, undefined, { sshLogger.error(`Jump host ${i + 1} not found`, undefined, {
operation: "jump_host_chain", operation: "jump_host_chain",
hostId: jumpHosts[i].hostId, hostId: jumpHosts[i].hostId,
@@ -148,6 +152,11 @@ async function createJumpHostChain(
clients.forEach((c) => c.end()); clients.forEach((c) => c.end());
return null; return null;
} }
}
// Connect through jump hosts sequentially
for (let i = 0; i < jumpHostConfigs.length; i++) {
const jumpHostConfig = jumpHostConfigs[i];
const jumpClient = new Client(); const jumpClient = new Client();
clients.push(jumpClient); clients.push(jumpClient);
@@ -623,7 +632,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
); );
cleanupSSH(connectionTimeout); cleanupSSH(connectionTimeout);
} }
}, 120000); }, 30000);
let resolvedCredentials = { password, key, keyPassword, keyType, authType }; let resolvedCredentials = { password, key, keyPassword, keyType, authType };
let authMethodNotAvailable = false; let authMethodNotAvailable = false;
@@ -1053,10 +1062,10 @@ wss.on("connection", async (ws: WebSocket, req) => {
tryKeyboard: true, tryKeyboard: true,
keepaliveInterval: 30000, keepaliveInterval: 30000,
keepaliveCountMax: 3, keepaliveCountMax: 3,
readyTimeout: 120000, readyTimeout: 30000,
tcpKeepAlive: true, tcpKeepAlive: true,
tcpKeepAliveInitialDelay: 30000, tcpKeepAliveInitialDelay: 30000,
timeout: 120000, timeout: 30000,
env: { env: {
TERM: "xterm-256color", TERM: "xterm-256color",
LANG: "en_US.UTF-8", LANG: "en_US.UTF-8",
@@ -1191,21 +1200,18 @@ wss.on("connection", async (ws: WebSocket, req) => {
if ( if (
hostConfig.useSocks5 && hostConfig.useSocks5 &&
(hostConfig.socks5Host || (hostConfig.socks5Host ||
(hostConfig.socks5ProxyChain && (hostConfig.socks5ProxyChain as any).length > 0)) (hostConfig.socks5ProxyChain &&
(hostConfig.socks5ProxyChain as any).length > 0))
) { ) {
try { try {
const socks5Socket = await createSocks5Connection( const socks5Socket = await createSocks5Connection(ip, port, {
ip, useSocks5: hostConfig.useSocks5,
port, socks5Host: hostConfig.socks5Host,
{ socks5Port: hostConfig.socks5Port,
useSocks5: hostConfig.useSocks5, socks5Username: hostConfig.socks5Username,
socks5Host: hostConfig.socks5Host, socks5Password: hostConfig.socks5Password,
socks5Port: hostConfig.socks5Port, socks5ProxyChain: hostConfig.socks5ProxyChain as any,
socks5Username: hostConfig.socks5Username, });
socks5Password: hostConfig.socks5Password,
socks5ProxyChain: hostConfig.socks5ProxyChain as any,
},
);
if (socks5Socket) { if (socks5Socket) {
connectConfig.sock = socks5Socket; connectConfig.sock = socks5Socket;

View File

@@ -637,7 +637,7 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
attemptReconnection(); attemptReconnection();
} }
} }
}, 10000); }, 15000);
ws.send( ws.send(
JSON.stringify({ JSON.stringify({
@@ -765,6 +765,7 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
...hostConfig.terminalConfig, ...hostConfig.terminalConfig,
}; };
// Send all environment variables immediately without delays
if ( if (
terminalConfig.environmentVariables && terminalConfig.environmentVariables &&
terminalConfig.environmentVariables.length > 0 terminalConfig.environmentVariables.length > 0
@@ -777,11 +778,11 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
data: `export ${envVar.key}="${envVar.value}"\n`, data: `export ${envVar.key}="${envVar.value}"\n`,
}), }),
); );
await new Promise((resolve) => setTimeout(resolve, 100));
} }
} }
} }
// Send startup snippet immediately after env vars
if (terminalConfig.startupSnippetId) { if (terminalConfig.startupSnippetId) {
try { try {
const snippets = await getSnippets(); const snippets = await getSnippets();
@@ -796,13 +797,13 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
data: snippet.content + "\n", data: snippet.content + "\n",
}), }),
); );
await new Promise((resolve) => setTimeout(resolve, 200));
} }
} catch (err) { } catch (err) {
console.warn("Failed to execute startup snippet:", err); console.warn("Failed to execute startup snippet:", err);
} }
} }
// Execute mosh command immediately if enabled
if (terminalConfig.autoMosh && ws.readyState === 1) { if (terminalConfig.autoMosh && ws.readyState === 1) {
ws.send( ws.send(
JSON.stringify({ JSON.stringify({
@@ -811,7 +812,7 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
}), }),
); );
} }
}, 500); }, 100);
} else if (msg.type === "disconnected") { } else if (msg.type === "disconnected") {
wasDisconnectedBySSH.current = true; wasDisconnectedBySSH.current = true;
setIsConnected(false); setIsConnected(false);
@@ -1405,41 +1406,34 @@ export const Terminal = forwardRef<TerminalHandle, SSHTerminalProps>(
setIsConnecting(true); setIsConnecting(true);
const readyFonts = // Start connection immediately without waiting for fonts
(document as { fonts?: { ready?: Promise<unknown> } }).fonts requestAnimationFrame(() => {
?.ready instanceof Promise fitAddonRef.current?.fit();
? (document as { fonts?: { ready?: Promise<unknown> } }).fonts.ready if (terminal && terminal.cols > 0 && terminal.rows > 0) {
: Promise.resolve(); scheduleNotify(terminal.cols, terminal.rows);
}
hardRefresh();
readyFonts.then(() => { setVisible(true);
requestAnimationFrame(() => { setIsReady(true);
fitAddonRef.current?.fit();
if (terminal && terminal.cols > 0 && terminal.rows > 0) {
scheduleNotify(terminal.cols, terminal.rows);
}
hardRefresh();
setVisible(true); if (terminal && !splitScreen) {
setIsReady(true); terminal.focus();
}
if (terminal && !splitScreen) { const jwtToken = getCookie("jwt");
terminal.focus();
}
const jwtToken = getCookie("jwt"); if (!jwtToken || jwtToken.trim() === "") {
setIsConnected(false);
setIsConnecting(false);
setConnectionError("Authentication required");
return;
}
if (!jwtToken || jwtToken.trim() === "") { const cols = terminal.cols;
setIsConnected(false); const rows = terminal.rows;
setIsConnecting(false);
setConnectionError("Authentication required");
return;
}
const cols = terminal.cols; connectToHost(cols, rows);
const rows = terminal.rows;
connectToHost(cols, rows);
});
}); });
}, [terminal, hostConfig, visible, isConnected, isConnecting, splitScreen]); }, [terminal, hostConfig, visible, isConnected, isConnecting, splitScreen]);