mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 21:03:47 +00:00
v2.0.0 (#621)
* 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>
This commit is contained in:
+280
-32
@@ -731,8 +731,9 @@ function getApiUrl(path: string, defaultPort: number): string {
|
||||
}
|
||||
|
||||
function initializeApiInstances() {
|
||||
// SSH Host Management API (port 30001)
|
||||
sshHostApi = createApiInstance(getApiUrl("/ssh", 30001), "SSH_HOST");
|
||||
// Host Management API (port 30001) - supports SSH, RDP, VNC, Telnet
|
||||
hostApi = createApiInstance(getApiUrl("/host", 30001), "HOST");
|
||||
sshHostApi = hostApi;
|
||||
|
||||
// Tunnel Management API (port 30003)
|
||||
tunnelApi = createApiInstance(getApiUrl("/ssh", 30003), "TUNNEL");
|
||||
@@ -759,7 +760,9 @@ function initializeApiInstances() {
|
||||
dockerApi = createApiInstance(getApiUrl("/docker", 30007), "DOCKER");
|
||||
}
|
||||
|
||||
// SSH Host Management API (port 30001)
|
||||
// Host Management API (port 30001) - supports SSH, RDP, VNC, Telnet
|
||||
export let hostApi: AxiosInstance;
|
||||
// Backward compatibility
|
||||
export let sshHostApi: AxiosInstance;
|
||||
|
||||
// Tunnel Management API (port 30003)
|
||||
@@ -1020,6 +1023,7 @@ export async function getSSHHosts(): Promise<SSHHostWithStatus[]> {
|
||||
export async function createSSHHost(hostData: SSHHostData): Promise<SSHHost> {
|
||||
try {
|
||||
const submitData = {
|
||||
connectionType: hostData.connectionType || "ssh",
|
||||
name: hostData.name || "",
|
||||
ip: hostData.ip,
|
||||
port: parseInt(hostData.port.toString()) || 22,
|
||||
@@ -1028,7 +1032,12 @@ export async function createSSHHost(hostData: SSHHostData): Promise<SSHHost> {
|
||||
tags: hostData.tags || [],
|
||||
pin: Boolean(hostData.pin),
|
||||
authType: hostData.authType,
|
||||
password: hostData.authType === "password" ? hostData.password : null,
|
||||
password:
|
||||
hostData.connectionType !== "ssh"
|
||||
? hostData.password || null
|
||||
: hostData.authType === "password"
|
||||
? hostData.password
|
||||
: null,
|
||||
key: hostData.authType === "key" ? hostData.key : null,
|
||||
keyPassword: hostData.authType === "key" ? hostData.keyPassword : null,
|
||||
keyType: hostData.authType === "key" ? hostData.keyType : null,
|
||||
@@ -1050,8 +1059,13 @@ export async function createSSHHost(hostData: SSHHostData): Promise<SSHHost> {
|
||||
quickActions: hostData.quickActions || [],
|
||||
sudoPassword: hostData.sudoPassword || null,
|
||||
statsConfig: hostData.statsConfig || null,
|
||||
dockerConfig: hostData.dockerConfig || null,
|
||||
terminalConfig: hostData.terminalConfig || null,
|
||||
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
|
||||
domain: hostData.domain || null,
|
||||
security: hostData.security || null,
|
||||
ignoreCert: Boolean(hostData.ignoreCert),
|
||||
guacamoleConfig: hostData.guacamoleConfig || null,
|
||||
notes: hostData.notes || "",
|
||||
useSocks5: Boolean(hostData.useSocks5),
|
||||
socks5Host: hostData.socks5Host || null,
|
||||
@@ -1096,6 +1110,7 @@ export async function updateSSHHost(
|
||||
): Promise<SSHHost> {
|
||||
try {
|
||||
const submitData = {
|
||||
connectionType: hostData.connectionType || "ssh",
|
||||
name: hostData.name || "",
|
||||
ip: hostData.ip,
|
||||
port: parseInt(hostData.port.toString()) || 22,
|
||||
@@ -1104,7 +1119,12 @@ export async function updateSSHHost(
|
||||
tags: hostData.tags || [],
|
||||
pin: Boolean(hostData.pin),
|
||||
authType: hostData.authType,
|
||||
password: hostData.authType === "password" ? hostData.password : null,
|
||||
password:
|
||||
hostData.connectionType !== "ssh"
|
||||
? hostData.password || null
|
||||
: hostData.authType === "password"
|
||||
? hostData.password
|
||||
: null,
|
||||
key: hostData.authType === "key" ? hostData.key : null,
|
||||
keyPassword: hostData.authType === "key" ? hostData.keyPassword : null,
|
||||
keyType: hostData.authType === "key" ? hostData.keyType : null,
|
||||
@@ -1126,8 +1146,13 @@ export async function updateSSHHost(
|
||||
quickActions: hostData.quickActions || [],
|
||||
sudoPassword: hostData.sudoPassword || null,
|
||||
statsConfig: hostData.statsConfig || null,
|
||||
dockerConfig: hostData.dockerConfig || null,
|
||||
terminalConfig: hostData.terminalConfig || null,
|
||||
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
|
||||
domain: hostData.domain || null,
|
||||
security: hostData.security || null,
|
||||
ignoreCert: Boolean(hostData.ignoreCert),
|
||||
guacamoleConfig: hostData.guacamoleConfig || null,
|
||||
notes: hostData.notes || "",
|
||||
useSocks5: Boolean(hostData.useSocks5),
|
||||
socks5Host: hostData.socks5Host || null,
|
||||
@@ -1511,7 +1536,6 @@ export async function connectSSH(
|
||||
});
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
// Preserve connection logs from error response
|
||||
if (error?.response?.data?.connectionLogs) {
|
||||
const errorWithLogs = new Error(
|
||||
error?.response?.data?.error ||
|
||||
@@ -1520,7 +1544,6 @@ export async function connectSSH(
|
||||
);
|
||||
(errorWithLogs as any).connectionLogs =
|
||||
error.response.data.connectionLogs;
|
||||
// Also preserve other fields like requires_totp
|
||||
if (error.response.data.requires_totp) {
|
||||
(errorWithLogs as any).requires_totp = true;
|
||||
(errorWithLogs as any).sessionId = error.response.data.sessionId;
|
||||
@@ -1653,7 +1676,7 @@ export async function quickConnect(
|
||||
data: Record<string, unknown>,
|
||||
): Promise<SSHHost> {
|
||||
try {
|
||||
const response = await authApi.post("/ssh/quick-connect", data);
|
||||
const response = await authApi.post("/host/quick-connect", data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw handleApiError(error, "quick connect");
|
||||
@@ -2135,7 +2158,7 @@ export async function getRecentFiles(
|
||||
hostId: number,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.get("/ssh/file_manager/recent", {
|
||||
const response = await authApi.get("/host/file_manager/recent", {
|
||||
params: { hostId },
|
||||
});
|
||||
return response.data;
|
||||
@@ -2151,7 +2174,7 @@ export async function addRecentFile(
|
||||
name?: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.post("/ssh/file_manager/recent", {
|
||||
const response = await authApi.post("/host/file_manager/recent", {
|
||||
hostId,
|
||||
path,
|
||||
name,
|
||||
@@ -2168,7 +2191,7 @@ export async function removeRecentFile(
|
||||
path: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.delete("/ssh/file_manager/recent", {
|
||||
const response = await authApi.delete("/host/file_manager/recent", {
|
||||
data: { hostId, path },
|
||||
});
|
||||
return response.data;
|
||||
@@ -2182,7 +2205,7 @@ export async function getPinnedFiles(
|
||||
hostId: number,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.get("/ssh/file_manager/pinned", {
|
||||
const response = await authApi.get("/host/file_manager/pinned", {
|
||||
params: { hostId },
|
||||
});
|
||||
return response.data;
|
||||
@@ -2198,7 +2221,7 @@ export async function addPinnedFile(
|
||||
name?: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.post("/ssh/file_manager/pinned", {
|
||||
const response = await authApi.post("/host/file_manager/pinned", {
|
||||
hostId,
|
||||
path,
|
||||
name,
|
||||
@@ -2215,7 +2238,7 @@ export async function removePinnedFile(
|
||||
path: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.delete("/ssh/file_manager/pinned", {
|
||||
const response = await authApi.delete("/host/file_manager/pinned", {
|
||||
data: { hostId, path },
|
||||
});
|
||||
return response.data;
|
||||
@@ -2229,7 +2252,7 @@ export async function getFolderShortcuts(
|
||||
hostId: number,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.get("/ssh/file_manager/shortcuts", {
|
||||
const response = await authApi.get("/host/file_manager/shortcuts", {
|
||||
params: { hostId },
|
||||
});
|
||||
return response.data;
|
||||
@@ -2245,7 +2268,7 @@ export async function addFolderShortcut(
|
||||
name?: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.post("/ssh/file_manager/shortcuts", {
|
||||
const response = await authApi.post("/host/file_manager/shortcuts", {
|
||||
hostId,
|
||||
path,
|
||||
name,
|
||||
@@ -2262,7 +2285,7 @@ export async function removeFolderShortcut(
|
||||
path: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.delete("/ssh/file_manager/shortcuts", {
|
||||
const response = await authApi.delete("/host/file_manager/shortcuts", {
|
||||
data: { hostId, path },
|
||||
});
|
||||
return response.data;
|
||||
@@ -2319,7 +2342,6 @@ export async function startMetricsPolling(hostId: number): Promise<{
|
||||
const response = await statsApi.post(`/metrics/start/${hostId}`);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
// Preserve connection logs from error response
|
||||
if (error?.response?.data?.connectionLogs) {
|
||||
const errorWithLogs = new Error(
|
||||
error?.response?.data?.error || error.message,
|
||||
@@ -2449,6 +2471,33 @@ export async function updateGlobalMonitoringSettings(settings: {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// GUACAMOLE SETTINGS
|
||||
// ============================================================================
|
||||
|
||||
export async function getGuacamoleSettings(): Promise<{
|
||||
enabled: boolean;
|
||||
url: string;
|
||||
}> {
|
||||
try {
|
||||
const response = await authApi.get("/users/guacamole-settings");
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
handleApiError(error, "fetch guacamole settings");
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateGuacamoleSettings(settings: {
|
||||
enabled?: boolean;
|
||||
url?: string;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
await authApi.patch("/users/guacamole-settings", settings);
|
||||
} catch (error) {
|
||||
handleApiError(error, "update guacamole settings");
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// AUTHENTICATION
|
||||
// ============================================================================
|
||||
@@ -2708,9 +2757,13 @@ export async function changePassword(oldPassword: string, newPassword: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getOIDCAuthorizeUrl(): Promise<OIDCAuthorize> {
|
||||
export async function getOIDCAuthorizeUrl(
|
||||
rememberMe = false,
|
||||
): Promise<OIDCAuthorize> {
|
||||
try {
|
||||
const response = await authApi.get("/users/oidc/authorize");
|
||||
const response = await authApi.get("/users/oidc/authorize", {
|
||||
params: { rememberMe },
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
handleApiError(error, "get OIDC authorize URL");
|
||||
@@ -3201,7 +3254,7 @@ export async function migrateHostToCredential(
|
||||
|
||||
export async function getFoldersWithStats(): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.get("/ssh/db/folders/with-stats");
|
||||
const response = await authApi.get("/host/db/folders/with-stats");
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
handleApiError(error, "fetch folders with statistics");
|
||||
@@ -3213,7 +3266,7 @@ export async function renameFolder(
|
||||
newName: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await authApi.put("/ssh/folders/rename", {
|
||||
const response = await authApi.put("/host/folders/rename", {
|
||||
oldName,
|
||||
newName,
|
||||
});
|
||||
@@ -3229,7 +3282,7 @@ export async function getSSHFolders(): Promise<SSHFolder[]> {
|
||||
operation: "fetch_ssh_folders",
|
||||
});
|
||||
|
||||
const response = await authApi.get("/ssh/folders");
|
||||
const response = await authApi.get("/host/folders");
|
||||
|
||||
sshLogger.success("SSH folders fetched successfully", {
|
||||
operation: "fetch_ssh_folders",
|
||||
@@ -3259,7 +3312,7 @@ export async function updateFolderMetadata(
|
||||
icon,
|
||||
});
|
||||
|
||||
await authApi.put("/ssh/folders/metadata", {
|
||||
await authApi.put("/host/folders/metadata", {
|
||||
name,
|
||||
color,
|
||||
icon,
|
||||
@@ -3289,7 +3342,7 @@ export async function deleteAllHostsInFolder(
|
||||
});
|
||||
|
||||
const response = await authApi.delete(
|
||||
`/ssh/folders/${encodeURIComponent(folderName)}/hosts`,
|
||||
`/host/folders/${encodeURIComponent(folderName)}/hosts`,
|
||||
);
|
||||
|
||||
sshLogger.success("All hosts in folder deleted successfully", {
|
||||
@@ -3596,7 +3649,15 @@ export interface UptimeInfo {
|
||||
export interface RecentActivityItem {
|
||||
id: number;
|
||||
userId: string;
|
||||
type: "terminal" | "file_manager" | "server_stats" | "tunnel" | "docker";
|
||||
type:
|
||||
| "terminal"
|
||||
| "file_manager"
|
||||
| "server_stats"
|
||||
| "tunnel"
|
||||
| "docker"
|
||||
| "telnet"
|
||||
| "vnc"
|
||||
| "rdp";
|
||||
hostId: number;
|
||||
hostName: string;
|
||||
timestamp: string;
|
||||
@@ -3625,7 +3686,15 @@ export async function getRecentActivity(
|
||||
}
|
||||
|
||||
export async function logActivity(
|
||||
type: "terminal" | "file_manager" | "server_stats" | "tunnel" | "docker",
|
||||
type:
|
||||
| "terminal"
|
||||
| "file_manager"
|
||||
| "server_stats"
|
||||
| "tunnel"
|
||||
| "docker"
|
||||
| "rdp"
|
||||
| "vnc"
|
||||
| "telnet",
|
||||
hostId: number,
|
||||
hostName: string,
|
||||
): Promise<{ message: string; id: number | string }> {
|
||||
@@ -3743,11 +3812,193 @@ export async function unlinkOIDCFromPasswordAccount(
|
||||
}
|
||||
}
|
||||
|
||||
export interface GuacamoleTokenRequest {
|
||||
protocol: "rdp" | "vnc" | "telnet";
|
||||
hostname: string;
|
||||
port?: number;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain?: string;
|
||||
security?: string;
|
||||
ignoreCert?: boolean;
|
||||
guacamoleConfig?: {
|
||||
colorDepth?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
dpi?: number;
|
||||
resizeMethod?: string;
|
||||
forceLossless?: boolean;
|
||||
disableAudio?: boolean;
|
||||
enableAudioInput?: boolean;
|
||||
enableWallpaper?: boolean;
|
||||
enableTheming?: boolean;
|
||||
enableFontSmoothing?: boolean;
|
||||
enableFullWindowDrag?: boolean;
|
||||
enableDesktopComposition?: boolean;
|
||||
enableMenuAnimations?: boolean;
|
||||
disableBitmapCaching?: boolean;
|
||||
disableOffscreenCaching?: boolean;
|
||||
disableGlyphCaching?: boolean;
|
||||
disableGfx?: boolean;
|
||||
enablePrinting?: boolean;
|
||||
printerName?: string;
|
||||
enableDrive?: boolean;
|
||||
driveName?: string;
|
||||
drivePath?: string;
|
||||
createDrivePath?: boolean;
|
||||
disableDownload?: boolean;
|
||||
disableUpload?: boolean;
|
||||
enableTouch?: boolean;
|
||||
clientName?: string;
|
||||
console?: boolean;
|
||||
initialProgram?: string;
|
||||
serverLayout?: string;
|
||||
timezone?: string;
|
||||
gatewayHostname?: string;
|
||||
gatewayPort?: number;
|
||||
gatewayUsername?: string;
|
||||
gatewayPassword?: string;
|
||||
gatewayDomain?: string;
|
||||
remoteApp?: string;
|
||||
remoteAppDir?: string;
|
||||
remoteAppArgs?: string;
|
||||
normalizeClipboard?: string;
|
||||
disableCopy?: boolean;
|
||||
disablePaste?: boolean;
|
||||
cursor?: string;
|
||||
swapRedBlue?: boolean;
|
||||
readOnly?: boolean;
|
||||
recordingPath?: string;
|
||||
recordingName?: string;
|
||||
createRecordingPath?: boolean;
|
||||
recordingExcludeOutput?: boolean;
|
||||
recordingExcludeMouse?: boolean;
|
||||
recordingIncludeKeys?: boolean;
|
||||
wolSendPacket?: boolean;
|
||||
wolMacAddr?: string;
|
||||
wolBroadcastAddr?: string;
|
||||
wolUdpPort?: number;
|
||||
wolWaitTime?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuacamoleTokenResponse {
|
||||
token: string;
|
||||
}
|
||||
|
||||
function toGuacamoleParams(
|
||||
config: GuacamoleTokenRequest["guacamoleConfig"],
|
||||
): Record<string, unknown> {
|
||||
if (!config) return {};
|
||||
|
||||
const params: Record<string, unknown> = {};
|
||||
|
||||
const mappings: Record<string, string> = {
|
||||
colorDepth: "color-depth",
|
||||
resizeMethod: "resize-method",
|
||||
forceLossless: "force-lossless",
|
||||
disableAudio: "disable-audio",
|
||||
enableAudioInput: "enable-audio-input",
|
||||
enableWallpaper: "enable-wallpaper",
|
||||
enableTheming: "enable-theming",
|
||||
enableFontSmoothing: "enable-font-smoothing",
|
||||
enableFullWindowDrag: "enable-full-window-drag",
|
||||
enableDesktopComposition: "enable-desktop-composition",
|
||||
enableMenuAnimations: "enable-menu-animations",
|
||||
disableBitmapCaching: "disable-bitmap-caching",
|
||||
disableOffscreenCaching: "disable-offscreen-caching",
|
||||
disableGlyphCaching: "disable-glyph-caching",
|
||||
disableGfx: "disable-gfx",
|
||||
enablePrinting: "enable-printing",
|
||||
printerName: "printer-name",
|
||||
enableDrive: "enable-drive",
|
||||
driveName: "drive-name",
|
||||
drivePath: "drive-path",
|
||||
createDrivePath: "create-drive-path",
|
||||
disableDownload: "disable-download",
|
||||
disableUpload: "disable-upload",
|
||||
enableTouch: "enable-touch",
|
||||
clientName: "client-name",
|
||||
initialProgram: "initial-program",
|
||||
serverLayout: "server-layout",
|
||||
gatewayHostname: "gateway-hostname",
|
||||
gatewayPort: "gateway-port",
|
||||
gatewayUsername: "gateway-username",
|
||||
gatewayPassword: "gateway-password",
|
||||
gatewayDomain: "gateway-domain",
|
||||
remoteApp: "remote-app",
|
||||
remoteAppDir: "remote-app-dir",
|
||||
remoteAppArgs: "remote-app-args",
|
||||
normalizeClipboard: "normalize-clipboard",
|
||||
disableCopy: "disable-copy",
|
||||
disablePaste: "disable-paste",
|
||||
swapRedBlue: "swap-red-blue",
|
||||
readOnly: "read-only",
|
||||
recordingPath: "recording-path",
|
||||
recordingName: "recording-name",
|
||||
createRecordingPath: "create-recording-path",
|
||||
recordingExcludeOutput: "recording-exclude-output",
|
||||
recordingExcludeMouse: "recording-exclude-mouse",
|
||||
recordingIncludeKeys: "recording-include-keys",
|
||||
wolSendPacket: "wol-send-packet",
|
||||
wolMacAddr: "wol-mac-addr",
|
||||
wolBroadcastAddr: "wol-broadcast-addr",
|
||||
wolUdpPort: "wol-udp-port",
|
||||
wolWaitTime: "wol-wait-time",
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(config)) {
|
||||
if (value !== undefined && value !== null && value !== "") {
|
||||
const paramName = mappings[key] || key;
|
||||
if (typeof value === "boolean") {
|
||||
params[paramName] = value ? "true" : "false";
|
||||
} else {
|
||||
params[paramName] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
export async function getGuacamoleToken(
|
||||
request: GuacamoleTokenRequest,
|
||||
): Promise<GuacamoleTokenResponse> {
|
||||
try {
|
||||
const guacParams = toGuacamoleParams(request.guacamoleConfig);
|
||||
|
||||
const response = await authApi.post("/guacamole/token", {
|
||||
type: request.protocol,
|
||||
hostname: request.hostname,
|
||||
port: request.port,
|
||||
username: request.username,
|
||||
password: request.password,
|
||||
domain: request.domain,
|
||||
security: request.security,
|
||||
"ignore-cert": request.ignoreCert,
|
||||
...guacParams,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw handleApiError(error, "get guacamole token");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getGuacamoleTokenFromHost(
|
||||
hostId: number,
|
||||
): Promise<GuacamoleTokenResponse> {
|
||||
try {
|
||||
const response = await authApi.post(`/guacamole/connect-host/${hostId}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw handleApiError(error, "get guacamole token from host");
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// RBAC MANAGEMENT
|
||||
// ============================================================================
|
||||
|
||||
// Role Management
|
||||
export async function getRoles(): Promise<{ roles: Role[] }> {
|
||||
try {
|
||||
const response = await rbacApi.get("/rbac/roles");
|
||||
@@ -3796,7 +4047,6 @@ export async function deleteRole(
|
||||
}
|
||||
}
|
||||
|
||||
// User-Role Management
|
||||
export async function getUserRoles(
|
||||
userId: string,
|
||||
): Promise<{ roles: UserRole[] }> {
|
||||
@@ -3836,14 +4086,13 @@ export async function removeRoleFromUser(
|
||||
}
|
||||
}
|
||||
|
||||
// Host Sharing Management
|
||||
export async function shareHost(
|
||||
hostId: number,
|
||||
shareData: {
|
||||
targetType: "user" | "role";
|
||||
targetUserId?: string;
|
||||
targetRoleId?: number;
|
||||
permissionLevel: "view"; // Only view permission is supported
|
||||
permissionLevel: "view";
|
||||
durationHours?: number;
|
||||
},
|
||||
): Promise<{ success: boolean }> {
|
||||
@@ -3932,7 +4181,6 @@ export async function connectDockerSession(
|
||||
if (error.response?.data?.requires_warpgate) {
|
||||
return error.response.data;
|
||||
}
|
||||
// Preserve connection logs from error response
|
||||
if (error?.response?.data?.connectionLogs) {
|
||||
const errorWithLogs = new Error(
|
||||
error?.response?.data?.error ||
|
||||
|
||||
Reference in New Issue
Block a user