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:
@@ -1,11 +1,12 @@
|
||||
import type { AuthenticatedRequest } from "../../../types/index.js";
|
||||
import express from "express";
|
||||
import { restartGuacServer } from "../../guacamole/guacamole-server.js";
|
||||
import crypto from "crypto";
|
||||
import { db } from "../db/index.js";
|
||||
import {
|
||||
users,
|
||||
sessions,
|
||||
sshData,
|
||||
hosts,
|
||||
sshCredentials,
|
||||
fileManagerRecent,
|
||||
fileManagerPinned,
|
||||
@@ -265,7 +266,7 @@ async function deleteUserAndRelatedData(userId: string): Promise<void> {
|
||||
|
||||
await db.delete(commandHistory).where(eq(commandHistory.userId, userId));
|
||||
|
||||
await db.delete(sshData).where(eq(sshData.userId, userId));
|
||||
await db.delete(hosts).where(eq(hosts.userId, userId));
|
||||
await db.delete(sshCredentials).where(eq(sshCredentials.userId, userId));
|
||||
|
||||
await db.delete(networkTopology).where(eq(networkTopology.userId, userId));
|
||||
@@ -789,6 +790,12 @@ router.get("/oidc-config/admin", requireAdmin, async (req, res) => {
|
||||
* description: Returns the OIDC authorization URL.
|
||||
* tags:
|
||||
* - Users
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: rememberMe
|
||||
* schema:
|
||||
* type: boolean
|
||||
* description: Whether to extend the session to 30 days instead of 2 hours.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OIDC authorization URL.
|
||||
@@ -799,29 +806,10 @@ router.get("/oidc-config/admin", requireAdmin, async (req, res) => {
|
||||
*/
|
||||
router.get("/oidc/authorize", async (req, res) => {
|
||||
try {
|
||||
const { rememberMe } = req.query;
|
||||
const origin = getRequestOriginWithForceHTTPS(req);
|
||||
const backendCallbackUri = `${origin}/users/oidc/callback`;
|
||||
|
||||
authLogger.info("OIDC authorize request headers", {
|
||||
protocol: req.protocol,
|
||||
host: req.get("Host"),
|
||||
origin: req.get("Origin"),
|
||||
referer: req.get("Referer"),
|
||||
"x-forwarded-proto": req.get("X-Forwarded-Proto"),
|
||||
"x-forwarded-host": req.get("X-Forwarded-Host"),
|
||||
"x-forwarded-port": req.get("X-Forwarded-Port"),
|
||||
secure: req.secure,
|
||||
calculatedOrigin: origin,
|
||||
backendCallbackUri: backendCallbackUri,
|
||||
});
|
||||
|
||||
authLogger.info(
|
||||
`\n${"=".repeat(68)}\n` +
|
||||
` OIDC CALLBACK URL - Register this in your OAuth provider:\n` +
|
||||
` ${backendCallbackUri}\n` +
|
||||
`${"=".repeat(68)}`,
|
||||
);
|
||||
|
||||
const envConfig = getOIDCConfigFromEnv();
|
||||
let config;
|
||||
|
||||
@@ -860,12 +848,12 @@ router.get("/oidc/authorize", async (req, res) => {
|
||||
.prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)")
|
||||
.run(`oidc_frontend_origin_${state}`, frontendOrigin);
|
||||
|
||||
authLogger.info("OIDC authorization initiated", {
|
||||
operation: "oidc_authorize",
|
||||
backendCallbackUri,
|
||||
frontendOrigin,
|
||||
referer,
|
||||
});
|
||||
db.$client
|
||||
.prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)")
|
||||
.run(
|
||||
`oidc_remember_me_${state}`,
|
||||
rememberMe === "true" ? "true" : "false",
|
||||
);
|
||||
|
||||
const authUrl = new URL(config.authorization_url);
|
||||
authUrl.searchParams.set("client_id", config.client_id);
|
||||
@@ -898,10 +886,6 @@ router.get("/oidc/authorize", async (req, res) => {
|
||||
*/
|
||||
router.get("/oidc/callback", async (req, res) => {
|
||||
const { code, state } = req.query;
|
||||
authLogger.info("OIDC login callback received", {
|
||||
operation: "oidc_login_request",
|
||||
state,
|
||||
});
|
||||
|
||||
if (!isNonEmptyString(code) || !isNonEmptyString(state)) {
|
||||
return res.status(400).json({ error: "Code and state are required" });
|
||||
@@ -913,6 +897,9 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
const storedFrontendOriginRow = db.$client
|
||||
.prepare("SELECT value FROM settings WHERE key = ?")
|
||||
.get(`oidc_frontend_origin_${state}`);
|
||||
const storedRememberMeRow = db.$client
|
||||
.prepare("SELECT value FROM settings WHERE key = ?")
|
||||
.get(`oidc_remember_me_${state}`);
|
||||
|
||||
if (!storedBackendCallbackRow || !storedFrontendOriginRow) {
|
||||
return res
|
||||
@@ -925,6 +912,8 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
).value as string;
|
||||
const frontendOrigin = (storedFrontendOriginRow as Record<string, unknown>)
|
||||
.value as string;
|
||||
const storedRememberMe =
|
||||
(storedRememberMeRow as Record<string, unknown> | null)?.value === "true";
|
||||
|
||||
try {
|
||||
const storedNonce = db.$client
|
||||
@@ -951,12 +940,6 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
);
|
||||
}
|
||||
|
||||
authLogger.info("OIDC token exchange attempt", {
|
||||
operation: "oidc_token_exchange",
|
||||
backendCallbackUri,
|
||||
frontendOrigin,
|
||||
});
|
||||
|
||||
const tokenResponse = await fetch(config.token_url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -998,6 +981,9 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
db.$client
|
||||
.prepare("DELETE FROM settings WHERE key = ?")
|
||||
.run(`oidc_frontend_origin_${state}`);
|
||||
db.$client
|
||||
.prepare("DELETE FROM settings WHERE key = ?")
|
||||
.run(`oidc_remember_me_${state}`);
|
||||
|
||||
let userInfo: Record<string, unknown> = null;
|
||||
const userInfoUrls: string[] = [];
|
||||
@@ -1320,6 +1306,7 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
const token = await authManager.generateJWTToken(userRecord.id, {
|
||||
deviceType: deviceInfo.type,
|
||||
deviceInfo: deviceInfo.deviceInfo,
|
||||
rememberMe: storedRememberMe,
|
||||
});
|
||||
|
||||
authLogger.success("OIDC login successful", {
|
||||
@@ -1334,7 +1321,9 @@ router.get("/oidc/callback", async (req, res) => {
|
||||
const maxAge =
|
||||
deviceInfo.type === "desktop" || deviceInfo.type === "mobile"
|
||||
? 30 * 24 * 60 * 60 * 1000
|
||||
: 2 * 60 * 60 * 1000;
|
||||
: storedRememberMe
|
||||
? 30 * 24 * 60 * 60 * 1000
|
||||
: 2 * 60 * 60 * 1000;
|
||||
|
||||
res.clearCookie("jwt", authManager.getClearCookieOptions(req));
|
||||
|
||||
@@ -2488,7 +2477,7 @@ router.post("/complete-reset", async (req, res) => {
|
||||
.delete(dismissedAlerts)
|
||||
.where(eq(dismissedAlerts.userId, userId));
|
||||
await db.delete(snippets).where(eq(snippets.userId, userId));
|
||||
await db.delete(sshData).where(eq(sshData.userId, userId));
|
||||
await db.delete(hosts).where(eq(hosts.userId, userId));
|
||||
await db
|
||||
.delete(sshCredentials)
|
||||
.where(eq(sshCredentials.userId, userId));
|
||||
@@ -4126,4 +4115,115 @@ router.post("/unlink-oidc-from-password", authenticateJWT, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /users/guacamole-settings:
|
||||
* get:
|
||||
* summary: Get Guacamole settings
|
||||
* description: Returns current guacd enabled status and host:port URL. No authentication required.
|
||||
* tags:
|
||||
* - Users
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Guacamole settings.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* enabled:
|
||||
* type: boolean
|
||||
* url:
|
||||
* type: string
|
||||
* 500:
|
||||
* description: Failed to get guacamole settings.
|
||||
*/
|
||||
router.get("/guacamole-settings", async (req, res) => {
|
||||
try {
|
||||
const enabledRow = db.$client
|
||||
.prepare("SELECT value FROM settings WHERE key = 'guac_enabled'")
|
||||
.get() as { value: string } | undefined;
|
||||
const urlRow = db.$client
|
||||
.prepare("SELECT value FROM settings WHERE key = 'guac_url'")
|
||||
.get() as { value: string } | undefined;
|
||||
res.json({
|
||||
enabled: enabledRow ? enabledRow.value !== "false" : true,
|
||||
url: urlRow ? urlRow.value : "guacd:4822",
|
||||
});
|
||||
} catch (err) {
|
||||
authLogger.error("Failed to get guacamole settings", err);
|
||||
res.status(500).json({ error: "Failed to get guacamole settings" });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /users/guacamole-settings:
|
||||
* patch:
|
||||
* summary: Update Guacamole settings
|
||||
* description: Admin-only. Updates guacd enabled status and/or host:port URL.
|
||||
* tags:
|
||||
* - Users
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* enabled:
|
||||
* type: boolean
|
||||
* url:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Guacamole settings updated.
|
||||
* 403:
|
||||
* description: Not authorized.
|
||||
* 500:
|
||||
* description: Failed to update guacamole settings.
|
||||
*/
|
||||
router.patch("/guacamole-settings", authenticateJWT, async (req, res) => {
|
||||
const userId = (req as AuthenticatedRequest).userId;
|
||||
try {
|
||||
const user = await db.select().from(users).where(eq(users.id, userId));
|
||||
if (!user || user.length === 0 || !user[0].isAdmin) {
|
||||
return res.status(403).json({ error: "Not authorized" });
|
||||
}
|
||||
const { enabled, url } = req.body;
|
||||
if (typeof enabled === "boolean") {
|
||||
db.$client
|
||||
.prepare(
|
||||
"INSERT OR REPLACE INTO settings (key, value) VALUES ('guac_enabled', ?)",
|
||||
)
|
||||
.run(enabled ? "true" : "false");
|
||||
}
|
||||
if (typeof url === "string") {
|
||||
db.$client
|
||||
.prepare(
|
||||
"INSERT OR REPLACE INTO settings (key, value) VALUES ('guac_url', ?)",
|
||||
)
|
||||
.run(url);
|
||||
try {
|
||||
await restartGuacServer();
|
||||
} catch (err) {
|
||||
authLogger.error("Failed to restart guac server after URL update", err);
|
||||
}
|
||||
}
|
||||
const enabledRow = db.$client
|
||||
.prepare("SELECT value FROM settings WHERE key = 'guac_enabled'")
|
||||
.get() as { value: string } | undefined;
|
||||
const urlRow = db.$client
|
||||
.prepare("SELECT value FROM settings WHERE key = 'guac_url'")
|
||||
.get() as { value: string } | undefined;
|
||||
res.json({
|
||||
enabled: enabledRow ? enabledRow.value !== "false" : true,
|
||||
url: urlRow ? urlRow.value : "guacd:4822",
|
||||
});
|
||||
} catch (err) {
|
||||
authLogger.error("Failed to update guacamole settings", err);
|
||||
res.status(500).json({ error: "Failed to update guacamole settings" });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user