v1.10.0 #471
@@ -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;
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user