fix: Sidebar resize issues and issues with TOTP interfering with password auth
This commit is contained in:
@@ -173,6 +173,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
|
||||
authType,
|
||||
credentialId,
|
||||
userProvidedPassword,
|
||||
forceKeyboardInteractive,
|
||||
} = req.body;
|
||||
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
@@ -257,39 +258,66 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
|
||||
|
||||
const config: Record<string, unknown> = {
|
||||
host: ip,
|
||||
port: port || 22,
|
||||
port,
|
||||
username,
|
||||
tryKeyboard: true,
|
||||
readyTimeout: 60000,
|
||||
keepaliveInterval: 30000,
|
||||
keepaliveCountMax: 3,
|
||||
readyTimeout: 60000,
|
||||
tcpKeepAlive: true,
|
||||
tcpKeepAliveInitialDelay: 30000,
|
||||
env: {
|
||||
TERM: "xterm-256color",
|
||||
LANG: "en_US.UTF-8",
|
||||
LC_ALL: "en_US.UTF-8",
|
||||
LC_CTYPE: "en_US.UTF-8",
|
||||
LC_MESSAGES: "en_US.UTF-8",
|
||||
LC_MONETARY: "en_US.UTF-8",
|
||||
LC_NUMERIC: "en_US.UTF-8",
|
||||
LC_TIME: "en_US.UTF-8",
|
||||
LC_COLLATE: "en_US.UTF-8",
|
||||
COLORTERM: "truecolor",
|
||||
},
|
||||
algorithms: {
|
||||
kex: [
|
||||
"curve25519-sha256",
|
||||
"curve25519-sha256@libssh.org",
|
||||
"ecdh-sha2-nistp521",
|
||||
"ecdh-sha2-nistp384",
|
||||
"ecdh-sha2-nistp256",
|
||||
"diffie-hellman-group-exchange-sha256",
|
||||
"diffie-hellman-group14-sha256",
|
||||
"diffie-hellman-group14-sha1",
|
||||
"diffie-hellman-group1-sha1",
|
||||
"diffie-hellman-group-exchange-sha256",
|
||||
"diffie-hellman-group-exchange-sha1",
|
||||
"ecdh-sha2-nistp256",
|
||||
"ecdh-sha2-nistp384",
|
||||
"ecdh-sha2-nistp521",
|
||||
"diffie-hellman-group1-sha1",
|
||||
],
|
||||
serverHostKey: [
|
||||
"ssh-ed25519",
|
||||
"ecdsa-sha2-nistp521",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp256",
|
||||
"rsa-sha2-512",
|
||||
"rsa-sha2-256",
|
||||
"ssh-rsa",
|
||||
"ssh-dss",
|
||||
],
|
||||
cipher: [
|
||||
"aes128-ctr",
|
||||
"aes192-ctr",
|
||||
"aes256-ctr",
|
||||
"aes128-gcm@openssh.com",
|
||||
"chacha20-poly1305@openssh.com",
|
||||
"aes256-gcm@openssh.com",
|
||||
"aes128-cbc",
|
||||
"aes192-cbc",
|
||||
"aes128-gcm@openssh.com",
|
||||
"aes256-ctr",
|
||||
"aes192-ctr",
|
||||
"aes128-ctr",
|
||||
"aes256-cbc",
|
||||
"aes192-cbc",
|
||||
"aes128-cbc",
|
||||
"3des-cbc",
|
||||
],
|
||||
hmac: [
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha1",
|
||||
"hmac-md5",
|
||||
],
|
||||
@@ -335,7 +363,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
|
||||
.json({ error: "Password required for password authentication" });
|
||||
}
|
||||
|
||||
if (userProvidedPassword) {
|
||||
if (!forceKeyboardInteractive) {
|
||||
config.password = resolvedCredentials.password;
|
||||
}
|
||||
} else if (resolvedCredentials.authType === "none") {
|
||||
@@ -413,27 +441,6 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
|
||||
});
|
||||
|
||||
client.on("error", (err) => {
|
||||
if (
|
||||
(err.message.includes("All configured authentication methods failed") ||
|
||||
err.message.includes("No authentication methods remaining")) &&
|
||||
resolvedCredentials.authType === "password" &&
|
||||
!config.password &&
|
||||
resolvedCredentials.password &&
|
||||
!userProvidedPassword
|
||||
) {
|
||||
fileLogger.info(
|
||||
"Retrying password auth with password method for file manager",
|
||||
{
|
||||
operation: "file_connect_retry",
|
||||
sessionId,
|
||||
hostId,
|
||||
},
|
||||
);
|
||||
config.password = resolvedCredentials.password;
|
||||
client.connect(config);
|
||||
return;
|
||||
}
|
||||
|
||||
if (responseSent) return;
|
||||
responseSent = true;
|
||||
fileLogger.error("SSH connection failed for file manager", {
|
||||
@@ -613,7 +620,6 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
|
||||
return "";
|
||||
});
|
||||
|
||||
keyboardInteractiveResponded = true;
|
||||
finish(responses);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -788,10 +788,26 @@ function addLegacyCredentials(
|
||||
function buildSshConfig(host: SSHHostWithCredentials): ConnectConfig {
|
||||
const base: ConnectConfig = {
|
||||
host: host.ip,
|
||||
port: host.port || 22,
|
||||
username: host.username || "root",
|
||||
port: host.port,
|
||||
username: host.username,
|
||||
tryKeyboard: true,
|
||||
readyTimeout: 10_000,
|
||||
keepaliveInterval: 30000,
|
||||
keepaliveCountMax: 3,
|
||||
readyTimeout: 60000,
|
||||
tcpKeepAlive: true,
|
||||
tcpKeepAliveInitialDelay: 30000,
|
||||
env: {
|
||||
TERM: "xterm-256color",
|
||||
LANG: "en_US.UTF-8",
|
||||
LC_ALL: "en_US.UTF-8",
|
||||
LC_CTYPE: "en_US.UTF-8",
|
||||
LC_MESSAGES: "en_US.UTF-8",
|
||||
LC_MONETARY: "en_US.UTF-8",
|
||||
LC_NUMERIC: "en_US.UTF-8",
|
||||
LC_TIME: "en_US.UTF-8",
|
||||
LC_COLLATE: "en_US.UTF-8",
|
||||
COLORTERM: "truecolor",
|
||||
},
|
||||
algorithms: {
|
||||
kex: [
|
||||
"curve25519-sha256",
|
||||
|
||||
@@ -30,6 +30,7 @@ interface ConnectToHostData {
|
||||
authType?: string;
|
||||
credentialId?: number;
|
||||
userId?: string;
|
||||
forceKeyboardInteractive?: boolean;
|
||||
};
|
||||
initialPath?: string;
|
||||
executeCommand?: string;
|
||||
@@ -149,6 +150,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
let pingInterval: NodeJS.Timeout | null = null;
|
||||
let keyboardInteractiveFinish: ((responses: string[]) => void) | null = null;
|
||||
let totpPromptSent = false;
|
||||
let isKeyboardInteractive = false;
|
||||
let keyboardInteractiveResponded = false;
|
||||
|
||||
ws.on("close", () => {
|
||||
@@ -362,10 +364,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
}
|
||||
});
|
||||
|
||||
async function handleConnectToHost(
|
||||
data: ConnectToHostData,
|
||||
retryWithPassword = false,
|
||||
) {
|
||||
async function handleConnectToHost(data: ConnectToHostData) {
|
||||
const { hostConfig, initialPath, executeCommand } = data;
|
||||
const {
|
||||
id,
|
||||
@@ -661,22 +660,6 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
sshConn.on("error", (err: Error) => {
|
||||
clearTimeout(connectionTimeout);
|
||||
|
||||
if (
|
||||
(err.message.includes("All configured authentication methods failed") ||
|
||||
err.message.includes("No authentication methods remaining")) &&
|
||||
resolvedCredentials.authType === "password" &&
|
||||
!retryWithPassword &&
|
||||
!(hostConfig as any).userProvidedPassword
|
||||
) {
|
||||
sshLogger.info("Retrying password auth with password method", {
|
||||
operation: "ssh_connect_retry",
|
||||
hostId: id,
|
||||
});
|
||||
cleanupSSH();
|
||||
handleConnectToHost(data, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(authMethodNotAvailable && resolvedCredentials.authType === "none") ||
|
||||
(resolvedCredentials.authType === "none" &&
|
||||
@@ -756,6 +739,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
prompts: Array<{ prompt: string; echo: boolean }>,
|
||||
finish: (responses: string[]) => void,
|
||||
) => {
|
||||
isKeyboardInteractive = true;
|
||||
const promptTexts = prompts.map((p) => p.prompt);
|
||||
const totpPromptIndex = prompts.findIndex((p) =>
|
||||
/verification code|verification_code|token|otp|2fa|authenticator|google.*auth/i.test(
|
||||
@@ -840,7 +824,6 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
return "";
|
||||
});
|
||||
|
||||
keyboardInteractiveResponded = true;
|
||||
finish(responses);
|
||||
}
|
||||
},
|
||||
@@ -931,7 +914,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((hostConfig as any).userProvidedPassword || retryWithPassword) {
|
||||
if (!hostConfig.forceKeyboardInteractive) {
|
||||
connectConfig.password = resolvedCredentials.password;
|
||||
}
|
||||
} else if (
|
||||
@@ -1033,6 +1016,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
}
|
||||
|
||||
totpPromptSent = false;
|
||||
isKeyboardInteractive = false;
|
||||
keyboardInteractiveResponded = false;
|
||||
keyboardInteractiveFinish = null;
|
||||
}
|
||||
|
||||
@@ -895,11 +895,24 @@ async function connectSSHTunnel(
|
||||
host: tunnelConfig.sourceIP,
|
||||
port: tunnelConfig.sourceSSHPort,
|
||||
username: tunnelConfig.sourceUsername,
|
||||
tryKeyboard: true,
|
||||
keepaliveInterval: 30000,
|
||||
keepaliveCountMax: 3,
|
||||
readyTimeout: 60000,
|
||||
tcpKeepAlive: true,
|
||||
tcpKeepAliveInitialDelay: 15000,
|
||||
tcpKeepAliveInitialDelay: 30000,
|
||||
env: {
|
||||
TERM: "xterm-256color",
|
||||
LANG: "en_US.UTF-8",
|
||||
LC_ALL: "en_US.UTF-8",
|
||||
LC_CTYPE: "en_US.UTF-8",
|
||||
LC_MESSAGES: "en_US.UTF-8",
|
||||
LC_MONETARY: "en_US.UTF-8",
|
||||
LC_NUMERIC: "en_US.UTF-8",
|
||||
LC_TIME: "en_US.UTF-8",
|
||||
LC_COLLATE: "en_US.UTF-8",
|
||||
COLORTERM: "truecolor",
|
||||
},
|
||||
algorithms: {
|
||||
kex: [
|
||||
"curve25519-sha256",
|
||||
|
||||
Reference in New Issue
Block a user