mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 04:43:36 +00:00
fix: add host issue, screen flickering issue, 2fa issue, open terminal session icon missing issue
This commit is contained in:
@@ -49,6 +49,50 @@ function isValidPort(port: unknown): port is number {
|
||||
return typeof port === "number" && port > 0 && port <= 65535;
|
||||
}
|
||||
|
||||
function transformHostResponse(
|
||||
host: Record<string, unknown>,
|
||||
): Record<string, unknown> {
|
||||
return {
|
||||
...host,
|
||||
tags:
|
||||
typeof host.tags === "string"
|
||||
? host.tags
|
||||
? host.tags.split(",").filter(Boolean)
|
||||
: []
|
||||
: [],
|
||||
pin: !!host.pin,
|
||||
enableTerminal: !!host.enableTerminal,
|
||||
enableTunnel: !!host.enableTunnel,
|
||||
enableFileManager: !!host.enableFileManager,
|
||||
enableDocker: !!host.enableDocker,
|
||||
showTerminalInSidebar: !!host.showTerminalInSidebar,
|
||||
showFileManagerInSidebar: !!host.showFileManagerInSidebar,
|
||||
showTunnelInSidebar: !!host.showTunnelInSidebar,
|
||||
showDockerInSidebar: !!host.showDockerInSidebar,
|
||||
showServerStatsInSidebar: !!host.showServerStatsInSidebar,
|
||||
tunnelConnections: host.tunnelConnections
|
||||
? JSON.parse(host.tunnelConnections as string)
|
||||
: [],
|
||||
jumpHosts: host.jumpHosts ? JSON.parse(host.jumpHosts as string) : [],
|
||||
quickActions: host.quickActions
|
||||
? JSON.parse(host.quickActions as string)
|
||||
: [],
|
||||
statsConfig: host.statsConfig
|
||||
? JSON.parse(host.statsConfig as string)
|
||||
: undefined,
|
||||
terminalConfig: host.terminalConfig
|
||||
? JSON.parse(host.terminalConfig as string)
|
||||
: undefined,
|
||||
dockerConfig: host.dockerConfig
|
||||
? JSON.parse(host.dockerConfig as string)
|
||||
: undefined,
|
||||
forceKeyboardInteractive: host.forceKeyboardInteractive === "true",
|
||||
socks5ProxyChain: host.socks5ProxyChain
|
||||
? JSON.parse(host.socks5ProxyChain as string)
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
const authManager = AuthManager.getInstance();
|
||||
const permissionManager = PermissionManager.getInstance();
|
||||
const authenticateJWT = authManager.createAuthMiddleware();
|
||||
@@ -461,34 +505,7 @@ router.post(
|
||||
}
|
||||
|
||||
const createdHost = result;
|
||||
const baseHost = {
|
||||
...createdHost,
|
||||
tags:
|
||||
typeof createdHost.tags === "string"
|
||||
? createdHost.tags
|
||||
? createdHost.tags.split(",").filter(Boolean)
|
||||
: []
|
||||
: [],
|
||||
pin: !!createdHost.pin,
|
||||
enableTerminal: !!createdHost.enableTerminal,
|
||||
enableTunnel: !!createdHost.enableTunnel,
|
||||
tunnelConnections: createdHost.tunnelConnections
|
||||
? JSON.parse(createdHost.tunnelConnections as string)
|
||||
: [],
|
||||
jumpHosts: createdHost.jumpHosts
|
||||
? JSON.parse(createdHost.jumpHosts as string)
|
||||
: [],
|
||||
enableFileManager: !!createdHost.enableFileManager,
|
||||
enableDocker: !!createdHost.enableDocker,
|
||||
showTerminalInSidebar: !!createdHost.showTerminalInSidebar,
|
||||
showFileManagerInSidebar: !!createdHost.showFileManagerInSidebar,
|
||||
showTunnelInSidebar: !!createdHost.showTunnelInSidebar,
|
||||
showDockerInSidebar: !!createdHost.showDockerInSidebar,
|
||||
showServerStatsInSidebar: !!createdHost.showServerStatsInSidebar,
|
||||
statsConfig: createdHost.statsConfig
|
||||
? JSON.parse(createdHost.statsConfig as string)
|
||||
: undefined,
|
||||
};
|
||||
const baseHost = transformHostResponse(createdHost);
|
||||
|
||||
const resolvedHost =
|
||||
(await resolveHostCredentials(baseHost, userId)) || baseHost;
|
||||
@@ -1067,37 +1084,7 @@ router.put(
|
||||
}
|
||||
|
||||
const updatedHost = updatedHosts[0];
|
||||
const baseHost = {
|
||||
...updatedHost,
|
||||
tags:
|
||||
typeof updatedHost.tags === "string"
|
||||
? updatedHost.tags
|
||||
? updatedHost.tags.split(",").filter(Boolean)
|
||||
: []
|
||||
: [],
|
||||
pin: !!updatedHost.pin,
|
||||
enableTerminal: !!updatedHost.enableTerminal,
|
||||
enableTunnel: !!updatedHost.enableTunnel,
|
||||
tunnelConnections: updatedHost.tunnelConnections
|
||||
? JSON.parse(updatedHost.tunnelConnections as string)
|
||||
: [],
|
||||
jumpHosts: updatedHost.jumpHosts
|
||||
? JSON.parse(updatedHost.jumpHosts as string)
|
||||
: [],
|
||||
enableFileManager: !!updatedHost.enableFileManager,
|
||||
enableDocker: !!updatedHost.enableDocker,
|
||||
showTerminalInSidebar: !!updatedHost.showTerminalInSidebar,
|
||||
showFileManagerInSidebar: !!updatedHost.showFileManagerInSidebar,
|
||||
showTunnelInSidebar: !!updatedHost.showTunnelInSidebar,
|
||||
showDockerInSidebar: !!updatedHost.showDockerInSidebar,
|
||||
showServerStatsInSidebar: !!updatedHost.showServerStatsInSidebar,
|
||||
statsConfig: updatedHost.statsConfig
|
||||
? JSON.parse(updatedHost.statsConfig as string)
|
||||
: undefined,
|
||||
dockerConfig: updatedHost.dockerConfig
|
||||
? JSON.parse(updatedHost.dockerConfig as string)
|
||||
: undefined,
|
||||
};
|
||||
const baseHost = transformHostResponse(updatedHost);
|
||||
|
||||
const resolvedHost =
|
||||
(await resolveHostCredentials(baseHost, userId)) || baseHost;
|
||||
@@ -1302,41 +1289,7 @@ router.get(
|
||||
const result = await Promise.all(
|
||||
data.map(async (row: Record<string, unknown>) => {
|
||||
const baseHost = {
|
||||
...row,
|
||||
tags:
|
||||
typeof row.tags === "string"
|
||||
? row.tags
|
||||
? row.tags.split(",").filter(Boolean)
|
||||
: []
|
||||
: [],
|
||||
pin: !!row.pin,
|
||||
enableTerminal: !!row.enableTerminal,
|
||||
enableTunnel: !!row.enableTunnel,
|
||||
tunnelConnections: row.tunnelConnections
|
||||
? JSON.parse(row.tunnelConnections as string)
|
||||
: [],
|
||||
jumpHosts: row.jumpHosts ? JSON.parse(row.jumpHosts as string) : [],
|
||||
quickActions: row.quickActions
|
||||
? JSON.parse(row.quickActions as string)
|
||||
: [],
|
||||
enableFileManager: !!row.enableFileManager,
|
||||
enableDocker: !!row.enableDocker,
|
||||
showTerminalInSidebar: !!row.showTerminalInSidebar,
|
||||
showFileManagerInSidebar: !!row.showFileManagerInSidebar,
|
||||
showTunnelInSidebar: !!row.showTunnelInSidebar,
|
||||
showDockerInSidebar: !!row.showDockerInSidebar,
|
||||
showServerStatsInSidebar: !!row.showServerStatsInSidebar,
|
||||
statsConfig: row.statsConfig
|
||||
? JSON.parse(row.statsConfig as string)
|
||||
: undefined,
|
||||
terminalConfig: row.terminalConfig
|
||||
? JSON.parse(row.terminalConfig as string)
|
||||
: undefined,
|
||||
forceKeyboardInteractive: row.forceKeyboardInteractive === "true",
|
||||
socks5ProxyChain: row.socks5ProxyChain
|
||||
? JSON.parse(row.socks5ProxyChain as string)
|
||||
: [],
|
||||
|
||||
...transformHostResponse(row),
|
||||
isShared: !!row.isShared,
|
||||
permissionLevel: row.permissionLevel || undefined,
|
||||
sharedExpiresAt: row.expiresAt || undefined,
|
||||
@@ -1417,39 +1370,7 @@ router.get(
|
||||
}
|
||||
|
||||
const host = data[0];
|
||||
const result = {
|
||||
...host,
|
||||
tags:
|
||||
typeof host.tags === "string"
|
||||
? host.tags
|
||||
? host.tags.split(",").filter(Boolean)
|
||||
: []
|
||||
: [],
|
||||
pin: !!host.pin,
|
||||
enableTerminal: !!host.enableTerminal,
|
||||
enableTunnel: !!host.enableTunnel,
|
||||
tunnelConnections: host.tunnelConnections
|
||||
? JSON.parse(host.tunnelConnections)
|
||||
: [],
|
||||
jumpHosts: host.jumpHosts ? JSON.parse(host.jumpHosts) : [],
|
||||
quickActions: host.quickActions ? JSON.parse(host.quickActions) : [],
|
||||
enableFileManager: !!host.enableFileManager,
|
||||
showTerminalInSidebar: !!host.showTerminalInSidebar,
|
||||
showFileManagerInSidebar: !!host.showFileManagerInSidebar,
|
||||
showTunnelInSidebar: !!host.showTunnelInSidebar,
|
||||
showDockerInSidebar: !!host.showDockerInSidebar,
|
||||
showServerStatsInSidebar: !!host.showServerStatsInSidebar,
|
||||
statsConfig: host.statsConfig
|
||||
? JSON.parse(host.statsConfig)
|
||||
: undefined,
|
||||
terminalConfig: host.terminalConfig
|
||||
? JSON.parse(host.terminalConfig)
|
||||
: undefined,
|
||||
forceKeyboardInteractive: host.forceKeyboardInteractive === "true",
|
||||
socks5ProxyChain: host.socks5ProxyChain
|
||||
? JSON.parse(host.socks5ProxyChain)
|
||||
: [],
|
||||
};
|
||||
const result = transformHostResponse(host);
|
||||
|
||||
res.json((await resolveHostCredentials(result, userId)) || result);
|
||||
} catch (err) {
|
||||
|
||||
@@ -1145,7 +1145,7 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
? 30 * 24 * 60 * 60 * 1000
|
||||
: 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
res.clearCookie("jwt", authManager.getSecureCookieOptions(req));
|
||||
res.clearCookie("jwt", authManager.getClearCookieOptions(req));
|
||||
|
||||
return res
|
||||
.cookie("jwt", token, authManager.getSecureCookieOptions(req, maxAge))
|
||||
@@ -1439,7 +1439,7 @@ router.post("/logout", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
|
||||
return res
|
||||
.clearCookie("jwt", authManager.getSecureCookieOptions(req))
|
||||
.clearCookie("jwt", authManager.getClearCookieOptions(req))
|
||||
.json({ success: true, message: "Logged out successfully" });
|
||||
} catch (err) {
|
||||
authLogger.error("Logout failed", err);
|
||||
|
||||
@@ -1284,7 +1284,10 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hostConfig.forceKeyboardInteractive) {
|
||||
connectConfig.password = resolvedCredentials.password;
|
||||
}
|
||||
|
||||
sendLog("auth", "info", "Using password authentication");
|
||||
} else if (
|
||||
resolvedCredentials.authType === "key" &&
|
||||
|
||||
@@ -518,6 +518,15 @@ class AuthManager {
|
||||
};
|
||||
}
|
||||
|
||||
getClearCookieOptions(req: RequestWithHeaders) {
|
||||
return {
|
||||
httpOnly: false,
|
||||
secure: req.secure || req.headers["x-forwarded-proto"] === "https",
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
};
|
||||
}
|
||||
|
||||
createAuthMiddleware() {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
const authReq = req as AuthenticatedRequest;
|
||||
|
||||
@@ -255,10 +255,6 @@ function AppContent({
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await logoutUser();
|
||||
|
||||
if (isElectron()) {
|
||||
localStorage.removeItem("jwt");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Logout failed:", error);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ export function Auth({
|
||||
"*",
|
||||
);
|
||||
setWebviewAuthSuccess(true);
|
||||
setTimeout(() => window.location.reload(), 100);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.error("Error posting auth success message:", e);
|
||||
}
|
||||
@@ -518,7 +518,6 @@ export function Auth({
|
||||
"*",
|
||||
);
|
||||
setWebviewAuthSuccess(true);
|
||||
setTimeout(() => window.location.reload(), 100);
|
||||
setTotpLoading(false);
|
||||
return;
|
||||
} catch (e) {
|
||||
@@ -655,7 +654,6 @@ export function Auth({
|
||||
"*",
|
||||
);
|
||||
setWebviewAuthSuccess(true);
|
||||
setTimeout(() => window.location.reload(), 100);
|
||||
setOidcLoading(false);
|
||||
return;
|
||||
} catch (e) {
|
||||
|
||||
+24
-2
@@ -1029,7 +1029,7 @@ export async function createSSHHost(hostData: SSHHostData): Promise<SSHHost> {
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
handleApiError(error, "create SSH host");
|
||||
throw handleApiError(error, "create SSH host");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1107,7 +1107,7 @@ export async function updateSSHHost(
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
handleApiError(error, "update SSH host");
|
||||
throw handleApiError(error, "update SSH host");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2381,8 +2381,30 @@ export async function logoutUser(): Promise<{
|
||||
}> {
|
||||
try {
|
||||
const response = await authApi.post("/users/logout");
|
||||
|
||||
if (isElectron()) {
|
||||
localStorage.removeItem("jwt");
|
||||
electronSettingsCache.delete("jwt");
|
||||
} else {
|
||||
const isSecure = window.location.protocol === "https:";
|
||||
const cookieString = isSecure
|
||||
? "jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; Secure; SameSite=Strict"
|
||||
: "jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict";
|
||||
document.cookie = cookieString;
|
||||
}
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
if (isElectron()) {
|
||||
localStorage.removeItem("jwt");
|
||||
electronSettingsCache.delete("jwt");
|
||||
} else {
|
||||
const isSecure = window.location.protocol === "https:";
|
||||
const cookieString = isSecure
|
||||
? "jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; Secure; SameSite=Strict"
|
||||
: "jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict";
|
||||
document.cookie = cookieString;
|
||||
}
|
||||
handleApiError(error, "logout user");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user