fix: Fixed various issues with the dashboard, tab bar, and database issues

This commit is contained in:
LukeGus
2025-10-21 22:09:05 -05:00
parent 21d8cf9b2c
commit 217af1e286
23 changed files with 757 additions and 254 deletions

View File

@@ -375,7 +375,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
scheduleSessionCleanup(sessionId);
res.json({ status: "success", message: "SSH connection established" });
// Log activity to homepage API
// Log activity to dashboard API
if (hostId && userId) {
(async () => {
try {
@@ -446,6 +446,8 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
cleanupSession(sessionId);
});
let keyboardInteractiveResponded = false;
client.on(
"keyboard-interactive",
(
@@ -455,11 +457,14 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
prompts: Array<{ prompt: string; echo: boolean }>,
finish: (responses: string[]) => void,
) => {
const promptTexts = prompts.map((p) => p.prompt);
fileLogger.info("Keyboard-interactive authentication requested", {
operation: "file_keyboard_interactive",
hostId,
sessionId,
promptsCount: prompts.length,
prompts: promptTexts,
alreadyResponded: keyboardInteractiveResponded,
});
const totpPromptIndex = prompts.findIndex((p) =>
@@ -469,7 +474,15 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
);
if (totpPromptIndex !== -1) {
if (responseSent) return;
// TOTP prompt detected - need user input
if (responseSent) {
fileLogger.warn("Response already sent, ignoring TOTP prompt", {
operation: "file_keyboard_interactive",
hostId,
sessionId,
});
return;
}
responseSent = true;
if (pendingTOTPSessions[sessionId]) {
@@ -481,11 +494,11 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
sessionId,
},
);
// Don't respond to duplicate keyboard-interactive events
// The first one is still being processed
return;
}
keyboardInteractiveResponded = true;
pendingTOTPSessions[sessionId] = {
client,
finish,
@@ -516,14 +529,40 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
prompt: prompts[totpPromptIndex].prompt,
});
} else {
if (resolvedCredentials.password) {
const responses = prompts.map(
() => resolvedCredentials.password || "",
// Non-TOTP prompts (password, etc.) - respond automatically
if (keyboardInteractiveResponded) {
fileLogger.warn(
"Already responded to keyboard-interactive, ignoring subsequent prompt",
{
operation: "file_keyboard_interactive",
hostId,
sessionId,
prompts: promptTexts,
},
);
finish(responses);
} else {
finish(prompts.map(() => ""));
return;
}
keyboardInteractiveResponded = true;
const responses = prompts.map((p) => {
if (/password/i.test(p.prompt) && resolvedCredentials.password) {
return resolvedCredentials.password;
}
return "";
});
fileLogger.info("Auto-responding to keyboard-interactive prompts", {
operation: "file_keyboard_interactive_response",
hostId,
sessionId,
hasPassword: !!resolvedCredentials.password,
responsesProvided: responses.filter((r) => r !== "").length,
totalPrompts: prompts.length,
prompts: promptTexts,
});
finish(responses);
}
},
);
@@ -640,7 +679,7 @@ app.post("/ssh/file_manager/ssh/connect-totp", async (req, res) => {
message: "TOTP verified, SSH connection established",
});
// Log activity to homepage API
// Log activity to dashboard API
if (session.hostId && session.userId) {
(async () => {
try {

View File

@@ -196,6 +196,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 keyboardInteractiveResponded = false;
ws.on("close", () => {
const userWs = userConnections.get(userId);
@@ -482,7 +483,29 @@ wss.on("connection", async (ws: WebSocket, req) => {
// Small delay to let connection stabilize after keyboard-interactive auth
// This helps prevent "No response from server" errors with TOTP
setTimeout(() => {
sshConn!.shell(
// Check if connection still exists (might have been cleaned up)
if (!sshConn) {
sshLogger.warn(
"SSH connection was cleaned up before shell could be created",
{
operation: "ssh_shell",
hostId: id,
ip,
port,
username,
},
);
ws.send(
JSON.stringify({
type: "error",
message:
"SSH connection was closed before terminal could be created",
}),
);
return;
}
sshConn.shell(
{
rows: data.rows,
cols: data.cols,
@@ -570,7 +593,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
JSON.stringify({ type: "connected", message: "SSH connected" }),
);
// Log activity to homepage API
// Log activity to dashboard API
if (id && hostConfig.userId) {
(async () => {
try {
@@ -714,8 +737,16 @@ wss.on("connection", async (ws: WebSocket, req) => {
);
if (totpPromptIndex !== -1) {
if (totpPromptSent) return;
// TOTP prompt detected - need user input
if (totpPromptSent) {
sshLogger.warn("TOTP prompt already sent, ignoring duplicate", {
operation: "ssh_keyboard_interactive",
hostId: id,
});
return;
}
totpPromptSent = true;
keyboardInteractiveResponded = true;
keyboardInteractiveFinish = (totpResponses: string[]) => {
const totpCode = (totpResponses[0] || "").trim();
@@ -748,6 +779,20 @@ wss.on("connection", async (ws: WebSocket, req) => {
}),
);
} else {
// Non-TOTP prompts (password, etc.) - respond automatically
if (keyboardInteractiveResponded) {
sshLogger.warn(
"Already responded to keyboard-interactive, ignoring subsequent prompt",
{
operation: "ssh_keyboard_interactive",
hostId: id,
prompts: promptTexts,
},
);
return;
}
keyboardInteractiveResponded = true;
const responses = prompts.map((p) => {
if (/password/i.test(p.prompt) && resolvedCredentials.password) {
return resolvedCredentials.password;
@@ -761,6 +806,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
hasPassword: !!resolvedCredentials.password,
responsesProvided: responses.filter((r) => r !== "").length,
totalPrompts: prompts.length,
prompts: promptTexts,
});
console.log(
@@ -948,6 +994,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
}
totpPromptSent = false;
keyboardInteractiveResponded = false;
keyboardInteractiveFinish = null;
}