mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-16 05:13:36 +00:00
e9e30cd318
* Guacd, Docker-Compose, RDP (#475) * fix select edit host but not update view (#438) * fix: Checksum issue with chocolatey * fix: Remove homebrew old stuff * Add Korean translation (#439) Co-authored-by: 송준우 <2484@coreit.co.kr> * feat: Automate flatpak * fix: Add imagemagik to electron builder to resolve build error * fix: Build error with runtime repo flag * fix: Flatpak runtime error and install freedesktop ver warning * fix: Flatpak runtime error and install freedesktop ver warning * feat: Re-add homebrew cask and move scripts to backend * fix: No sandbox flag issue * fix: Change name for electron macos cask output * fix: Sandbox error with Linux * fix: Remove comming soon for app stores in readme * Adding Comment at the end of the public_key on the host on deploy (#440) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * -Add New Interface for Credential DB -Add Credential Name as a comment into the server authorized_key file --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Sudo auto fill password (#441) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Feature Sudo password auto-fill; * Fix locale json shema; --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Added Italian Language; (#445) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Added Italian Language; --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Auto collapse snippet folders (#448) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * feat: Add collapsable snippets (customizable in user profile) * Translations (#447) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Added Italian Language; * Fix translations; Removed duplicate keys, synchronised other languages using English as the source, translated added keys, fixed inaccurate translations. --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Remove PTY-level keepalive (#449) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Remove PTY-level keepalive to prevent unwanted terminal output; use SSH-level keepalive instead --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * feat: add Guacamole support for RDP, VNC, and Telnet connections - Implemented WebSocket support for Guacamole in Nginx configuration. - Added REST API endpoints for generating connection tokens and checking guacd status. - Created Guacamole server using guacamole-lite for handling connections. - Developed frontend components for testing RDP/VNC connections and displaying the remote session. - Updated package dependencies to include guacamole-common-js and guacamole-lite. - Enhanced logging for Guacamole operations. * feat: enhance Guacamole support with RDP and VNC connection settings and UI updates * feat: Seperate server stats and tunnel management (improved both UI's) then started initial docker implementation * fix: finalize adding docker to db * fix: merge syntax errors * feat: implement mouse coordinate adjustment based on scale factor in GuacamoleDisplay * feat: add TypeScript definitions for guacamole-common-js module * feat: enhance Mouse.State constructor to accept optional parameters and object destructuring * feat: Add support for RDP and VNC connections in SSH host management - Introduced connectionType field to differentiate between SSH, RDP, VNC, and Telnet in host data structures. - Updated backend routes to handle RDP/VNC specific fields: domain, security, and ignoreCert. - Enhanced the HostManagerEditor to include RDP/VNC specific settings and authentication options. - Implemented token retrieval for RDP/VNC connections using Guacamole API. - Updated UI components to reflect connection type changes and provide appropriate connection buttons. - Removed the GuacamoleTestDialog component as its functionality is integrated into the HostManagerEditor. - Adjusted the TopNavbar and Host components to accommodate new connection types and their respective actions. * feat: Enhance Guacamole integration with extended configuration options - Added detailed Guacamole configuration interface for RDP/VNC/Telnet connections, including display, audio, performance, and session settings. - Implemented logging for token requests and received options for better debugging. - Updated HostManagerEditor to support new Guacamole configuration fields with validation and default values. - Integrated Guacamole configuration parsing in HostManagerViewer and Host components. - Enhanced API requests to include extended Guacamole configuration parameters in the token request. - Refactored code to convert camelCase configuration keys to kebab-case for compatibility with Guacamole API. * feat: merge guacd into 2.0.0 and improve UI for host manager and made general bug fixes --------- Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com> Co-authored-by: LukeGus <bugattiguy527@gmail.com> Co-authored-by: junu <bigdwarf_@naver.com> Co-authored-by: 송준우 <2484@coreit.co.kr> Co-authored-by: SlimGary <trash.slim@gmail.com> Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: rename api routes and files * feat: improve guacd ui/backend * feat: improve guacd ui/backend * fix: state persistance issues causing refresh * feat: improge guacd connections, fixed telnet not opening, and improved general guacd integration * feat: continue improving integration also with bug fixes * Merge 2.0.0 with 2.0.0 that includes bug fixes (#620) * Guacd, Docker-Compose, RDP (#475) * fix select edit host but not update view (#438) * fix: Checksum issue with chocolatey * fix: Remove homebrew old stuff * Add Korean translation (#439) Co-authored-by: 송준우 <2484@coreit.co.kr> * feat: Automate flatpak * fix: Add imagemagik to electron builder to resolve build error * fix: Build error with runtime repo flag * fix: Flatpak runtime error and install freedesktop ver warning * fix: Flatpak runtime error and install freedesktop ver warning * feat: Re-add homebrew cask and move scripts to backend * fix: No sandbox flag issue * fix: Change name for electron macos cask output * fix: Sandbox error with Linux * fix: Remove comming soon for app stores in readme * Adding Comment at the end of the public_key on the host on deploy (#440) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * -Add New Interface for Credential DB -Add Credential Name as a comment into the server authorized_key file --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Sudo auto fill password (#441) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Feature Sudo password auto-fill; * Fix locale json shema; --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Added Italian Language; (#445) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Added Italian Language; --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Auto collapse snippet folders (#448) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * feat: Add collapsable snippets (customizable in user profile) * Translations (#447) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Added Italian Language; * Fix translations; Removed duplicate keys, synchronised other languages using English as the source, translated added keys, fixed inaccurate translations. --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Remove PTY-level keepalive (#449) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Remove PTY-level keepalive to prevent unwanted terminal output; use SSH-level keepalive instead --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * feat: add Guacamole support for RDP, VNC, and Telnet connections - Implemented WebSocket support for Guacamole in Nginx configuration. - Added REST API endpoints for generating connection tokens and checking guacd status. - Created Guacamole server using guacamole-lite for handling connections. - Developed frontend components for testing RDP/VNC connections and displaying the remote session. - Updated package dependencies to include guacamole-common-js and guacamole-lite. - Enhanced logging for Guacamole operations. * feat: enhance Guacamole support with RDP and VNC connection settings and UI updates * feat: Seperate server stats and tunnel management (improved both UI's) then started initial docker implementation * fix: finalize adding docker to db * fix: merge syntax errors * feat: implement mouse coordinate adjustment based on scale factor in GuacamoleDisplay * feat: add TypeScript definitions for guacamole-common-js module * feat: enhance Mouse.State constructor to accept optional parameters and object destructuring * feat: Add support for RDP and VNC connections in SSH host management - Introduced connectionType field to differentiate between SSH, RDP, VNC, and Telnet in host data structures. - Updated backend routes to handle RDP/VNC specific fields: domain, security, and ignoreCert. - Enhanced the HostManagerEditor to include RDP/VNC specific settings and authentication options. - Implemented token retrieval for RDP/VNC connections using Guacamole API. - Updated UI components to reflect connection type changes and provide appropriate connection buttons. - Removed the GuacamoleTestDialog component as its functionality is integrated into the HostManagerEditor. - Adjusted the TopNavbar and Host components to accommodate new connection types and their respective actions. * feat: Enhance Guacamole integration with extended configuration options - Added detailed Guacamole configuration interface for RDP/VNC/Telnet connections, including display, audio, performance, and session settings. - Implemented logging for token requests and received options for better debugging. - Updated HostManagerEditor to support new Guacamole configuration fields with validation and default values. - Integrated Guacamole configuration parsing in HostManagerViewer and Host components. - Enhanced API requests to include extended Guacamole configuration parameters in the token request. - Refactored code to convert camelCase configuration keys to kebab-case for compatibility with Guacamole API. * feat: merge guacd into 2.0.0 and improve UI for host manager and made general bug fixes --------- Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com> Co-authored-by: LukeGus <bugattiguy527@gmail.com> Co-authored-by: junu <bigdwarf_@naver.com> Co-authored-by: 송준우 <2484@coreit.co.kr> Co-authored-by: SlimGary <trash.slim@gmail.com> Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: rename api routes and files * feat: improve guacd ui/backend * feat: improve guacd ui/backend * fix: state persistance issues causing refresh * feat: improge guacd connections, fixed telnet not opening, and improved general guacd integration * feat: continue improving integration also with bug fixes --------- Co-authored-by: Wesley Reid <starhound@lostsouls.org> Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com> Co-authored-by: junu <bigdwarf_@naver.com> Co-authored-by: 송준우 <2484@coreit.co.kr> Co-authored-by: SlimGary <trash.slim@gmail.com> Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> * feat: allow customizing guacd backened url * fix: ssh route mistmatching and guacamole url not changing * chore: increment ver * feat: change default to work with default compose, added splits creen support, updated readmes * fix: linux app not starting due to better sqlite isuses, improved copy/paste system so no context menu, added oidc remember me toggle, improved OS detection for sessions, flatpak invalid key, and sharing hosts with other users errors * fix: global settings not setting * chore: update compose * feat: improve the global status input * chore: cleanup files * chore: update export/improt with new host fields * fix: file manager and docker not loading properly --------- Co-authored-by: Wesley Reid <starhound@lostsouls.org> Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com> Co-authored-by: junu <bigdwarf_@naver.com> Co-authored-by: 송준우 <2484@coreit.co.kr> Co-authored-by: SlimGary <trash.slim@gmail.com> Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
304 lines
8.7 KiB
TypeScript
304 lines
8.7 KiB
TypeScript
import express from "express";
|
|
import { GuacamoleTokenService } from "./token-service.js";
|
|
import { guacLogger } from "../utils/logger.js";
|
|
import { AuthManager } from "../utils/auth-manager.js";
|
|
import { PermissionManager } from "../utils/permission-manager.js";
|
|
import { SimpleDBOps } from "../utils/simple-db-ops.js";
|
|
import { getDb } from "../database/db/index.js";
|
|
import { hosts } from "../database/db/schema.js";
|
|
import { eq, and } from "drizzle-orm";
|
|
import type { AuthenticatedRequest } from "../../types/index.js";
|
|
|
|
const router = express.Router();
|
|
const tokenService = GuacamoleTokenService.getInstance();
|
|
const authManager = AuthManager.getInstance();
|
|
|
|
router.use(authManager.createAuthMiddleware());
|
|
|
|
/**
|
|
* POST /guacamole/token
|
|
* Generate an encrypted connection token for guacamole-lite
|
|
*
|
|
* Body: {
|
|
* type: "rdp" | "vnc" | "telnet",
|
|
* hostname: string,
|
|
* port?: number,
|
|
* username?: string,
|
|
* password?: string,
|
|
* domain?: string,
|
|
* // Additional protocol-specific options
|
|
* }
|
|
*/
|
|
router.post("/token", async (req, res) => {
|
|
try {
|
|
const userId = (req as AuthenticatedRequest).userId;
|
|
const { type, hostname, port, username, password, domain, ...options } =
|
|
req.body;
|
|
|
|
if (!type || !hostname) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "Missing required fields: type and hostname" });
|
|
}
|
|
|
|
if (!["rdp", "vnc", "telnet"].includes(type)) {
|
|
return res.status(400).json({
|
|
error: "Invalid connection type. Must be rdp, vnc, or telnet",
|
|
});
|
|
}
|
|
|
|
let token: string;
|
|
|
|
switch (type) {
|
|
case "rdp":
|
|
token = tokenService.createRdpToken(
|
|
hostname,
|
|
username || "",
|
|
password || "",
|
|
{
|
|
port: port || 3389,
|
|
domain,
|
|
...options,
|
|
},
|
|
);
|
|
break;
|
|
case "vnc":
|
|
token = tokenService.createVncToken(hostname, password, {
|
|
port: port || 5900,
|
|
...options,
|
|
});
|
|
break;
|
|
case "telnet":
|
|
token = tokenService.createTelnetToken(hostname, username, password, {
|
|
port: port || 23,
|
|
...options,
|
|
});
|
|
break;
|
|
default:
|
|
return res.status(400).json({ error: "Invalid connection type" });
|
|
}
|
|
|
|
res.json({ token });
|
|
} catch (error) {
|
|
guacLogger.error("Failed to generate guacamole token", error, {
|
|
operation: "guac_token_error",
|
|
});
|
|
res.status(500).json({ error: "Failed to generate connection token" });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @openapi
|
|
* /guacamole/connect-host/{hostId}:
|
|
* post:
|
|
* summary: Generate Guacamole connection token from host configuration
|
|
* description: Fetches host configuration from database and generates a connection token for RDP/VNC/Telnet
|
|
* tags:
|
|
* - Guacamole
|
|
* security:
|
|
* - bearerAuth: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: hostId
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* description: Host ID to connect to
|
|
* responses:
|
|
* 200:
|
|
* description: Connection token generated successfully
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* properties:
|
|
* token:
|
|
* type: string
|
|
* description: Encrypted connection token
|
|
* 400:
|
|
* description: Invalid request or unsupported connection type
|
|
* 403:
|
|
* description: Access denied to host
|
|
* 404:
|
|
* description: Host not found
|
|
* 500:
|
|
* description: Server error
|
|
*/
|
|
router.post(
|
|
"/connect-host/:hostId",
|
|
async (req: express.Request, res: express.Response) => {
|
|
try {
|
|
const userId = (req as AuthenticatedRequest).userId!;
|
|
const hostId = parseInt(req.params.hostId, 10);
|
|
|
|
if (!hostId || isNaN(hostId)) {
|
|
return res.status(400).json({ error: "Invalid host ID" });
|
|
}
|
|
|
|
const hostResults = await SimpleDBOps.select(
|
|
getDb().select().from(hosts).where(eq(hosts.id, hostId)),
|
|
"ssh_data",
|
|
userId,
|
|
);
|
|
|
|
if (hostResults.length === 0) {
|
|
return res.status(404).json({ error: "Host not found" });
|
|
}
|
|
|
|
const host = hostResults[0];
|
|
|
|
if (host.userId !== userId) {
|
|
const permissionManager = PermissionManager.getInstance();
|
|
const accessInfo = await permissionManager.canAccessHost(
|
|
userId,
|
|
hostId,
|
|
"read",
|
|
);
|
|
|
|
if (!accessInfo.hasAccess) {
|
|
guacLogger.warn("User attempted to access host without permission", {
|
|
operation: "guac_access_denied",
|
|
userId,
|
|
hostId,
|
|
});
|
|
return res.status(403).json({ error: "Access denied to this host" });
|
|
}
|
|
}
|
|
|
|
const connectionType = (host.connectionType as string) || "ssh";
|
|
if (!["rdp", "vnc", "telnet"].includes(connectionType)) {
|
|
return res.status(400).json({
|
|
error: `Connection type '${connectionType}' is not supported for remote desktop. Only RDP, VNC, and Telnet are supported.`,
|
|
});
|
|
}
|
|
|
|
let guacConfig: Record<string, unknown> = {};
|
|
if (host.guacamoleConfig) {
|
|
try {
|
|
guacConfig =
|
|
typeof host.guacamoleConfig === "string"
|
|
? JSON.parse(host.guacamoleConfig as string)
|
|
: (host.guacamoleConfig as Record<string, unknown>);
|
|
} catch (error) {
|
|
guacLogger.warn("Failed to parse guacamole config", {
|
|
operation: "guac_config_parse_error",
|
|
hostId,
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
});
|
|
}
|
|
}
|
|
|
|
let token: string;
|
|
const hostname = host.ip as string;
|
|
const port = host.port as number;
|
|
const username = (host.username as string) || "";
|
|
const password = (host.password as string) || "";
|
|
const domain = (host.domain as string) || "";
|
|
|
|
switch (connectionType) {
|
|
case "rdp":
|
|
token = tokenService.createRdpToken(hostname, username, password, {
|
|
port: port || 3389,
|
|
domain,
|
|
security: (host.security as string) || undefined,
|
|
"ignore-cert": (host.ignoreCert as boolean) || false,
|
|
...guacConfig,
|
|
});
|
|
break;
|
|
case "vnc":
|
|
token = tokenService.createVncToken(hostname, password, {
|
|
port: port || 5900,
|
|
...guacConfig,
|
|
});
|
|
break;
|
|
case "telnet":
|
|
token = tokenService.createTelnetToken(hostname, username, password, {
|
|
port: port || 23,
|
|
...guacConfig,
|
|
});
|
|
break;
|
|
default:
|
|
return res.status(400).json({ error: "Invalid connection type" });
|
|
}
|
|
|
|
res.json({ token });
|
|
} catch (error) {
|
|
guacLogger.error("Failed to generate guacamole token for host", error, {
|
|
operation: "guac_host_token_error",
|
|
});
|
|
res.status(500).json({ error: "Failed to generate connection token" });
|
|
}
|
|
},
|
|
);
|
|
|
|
/**
|
|
* GET /guacamole/status
|
|
* Check if guacd is reachable
|
|
*/
|
|
router.get("/status", async (req, res) => {
|
|
try {
|
|
let guacdHost = process.env.GUACD_HOST || "localhost";
|
|
let guacdPort = parseInt(process.env.GUACD_PORT || "4822", 10);
|
|
try {
|
|
const db = getDb();
|
|
const urlRow = db.$client
|
|
.prepare("SELECT value FROM settings WHERE key = 'guac_url'")
|
|
.get() as { value: string } | undefined;
|
|
if (urlRow?.value) {
|
|
const parts = urlRow.value.split(":");
|
|
guacdHost = parts[0] || guacdHost;
|
|
guacdPort = parseInt(parts[1] || String(guacdPort), 10);
|
|
}
|
|
} catch {
|
|
// Fall back to env vars
|
|
}
|
|
|
|
const net = await import("net");
|
|
|
|
const checkConnection = (): Promise<boolean> => {
|
|
return new Promise((resolve) => {
|
|
const socket = new net.Socket();
|
|
socket.setTimeout(3000);
|
|
|
|
socket.on("connect", () => {
|
|
socket.destroy();
|
|
resolve(true);
|
|
});
|
|
|
|
socket.on("timeout", () => {
|
|
socket.destroy();
|
|
resolve(false);
|
|
});
|
|
|
|
socket.on("error", () => {
|
|
socket.destroy();
|
|
resolve(false);
|
|
});
|
|
|
|
socket.connect(guacdPort, guacdHost);
|
|
});
|
|
};
|
|
|
|
const isConnected = await checkConnection();
|
|
|
|
res.json({
|
|
guacd: {
|
|
host: guacdHost,
|
|
port: guacdPort,
|
|
status: isConnected ? "connected" : "disconnected",
|
|
},
|
|
websocket: {
|
|
port: 30008,
|
|
status: "running",
|
|
},
|
|
});
|
|
} catch (error) {
|
|
guacLogger.error("Failed to check guacamole status", error, {
|
|
operation: "guac_status_error",
|
|
});
|
|
res.status(500).json({ error: "Failed to check status" });
|
|
}
|
|
});
|
|
|
|
export default router;
|