From 718b3437130b32d6e552d593a19eef4b601cbf35 Mon Sep 17 00:00:00 2001 From: Alex Goodkind Date: Tue, 27 May 2025 08:28:51 -0700 Subject: [PATCH] feat: add local web server loopback mode configuration (#511) * feat: add local web server loopback mode configuration - Introduced a new configuration option `LocalWebServerLoopbackOnly` to restrict the web server to listen only on the loopback interface. - Added RPC methods `rpcGetLocalWebServerLoopbackOnly` and `rpcSetLocalWebServerLoopbackOnly` for retrieving and updating this setting. - Updated the web server startup logic to bind to the appropriate address based on the new configuration. - Modified the `LocalDevice` struct to include the loopback setting in the response. * remove extra logs * chore: add VSCode extensions for improved development environment * refactor: rename LocalWebServerLoopbackOnly to LocalLoopbackOnly - Updated the configuration struct and related RPC methods to use the new name `LocalLoopbackOnly` for clarity. - Adjusted the web server binding logic and device response structure to reflect this change. * feat: add loopback-only mode functionality to UI - Implemented a new setting for enabling loopback-only mode, restricting web interface access to localhost. - Added a confirmation dialog to warn users before enabling this feature. - Updated the ConfirmDialog component to accept React nodes for the description prop. - Refactored imports and adjusted component structure for clarity. * refactor: optimize device settings handlers for better performance - Refactored the `handleDevChannelChange` and `handleLoopbackOnlyModeChange` functions to use `useCallback` for improved performance and to prevent unnecessary re-renders. - Consolidated the logic for applying loopback-only mode into a separate `applyLoopbackOnlyMode` function, enhancing code clarity and maintainability. - Updated the confirmation flow for enabling loopback-only mode to ensure user warnings are displayed appropriately. --- config.go | 1 + jsonrpc.go | 21 +++ ui/src/components/ConfirmDialog.tsx | 12 +- .../routes/devices.$id.settings.advanced.tsx | 125 +++++++++++++++--- web.go | 20 ++- 5 files changed, 148 insertions(+), 31 deletions(-) diff --git a/config.go b/config.go index e699ff3..04f2a4e 100644 --- a/config.go +++ b/config.go @@ -85,6 +85,7 @@ type Config struct { HashedPassword string `json:"hashed_password"` LocalAuthToken string `json:"local_auth_token"` LocalAuthMode string `json:"localAuthMode"` //TODO: fix it with migration + LocalLoopbackOnly bool `json:"local_loopback_only"` WakeOnLanDevices []WakeOnLanDevice `json:"wake_on_lan_devices"` KeyboardMacros []KeyboardMacro `json:"keyboard_macros"` KeyboardLayout string `json:"keyboard_layout"` diff --git a/jsonrpc.go b/jsonrpc.go index a32cab2..258828a 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -1006,6 +1006,25 @@ func setKeyboardMacros(params KeyboardMacrosParams) (interface{}, error) { return nil, nil } +func rpcGetLocalLoopbackOnly() (bool, error) { + return config.LocalLoopbackOnly, nil +} + +func rpcSetLocalLoopbackOnly(enabled bool) error { + // Check if the setting is actually changing + if config.LocalLoopbackOnly == enabled { + return nil + } + + // Update the setting + config.LocalLoopbackOnly = enabled + if err := SaveConfig(); err != nil { + return fmt.Errorf("failed to save config: %w", err) + } + + return nil +} + var rpcHandlers = map[string]RPCHandler{ "ping": {Func: rpcPing}, "reboot": {Func: rpcReboot, Params: []string{"force"}}, @@ -1083,4 +1102,6 @@ var rpcHandlers = map[string]RPCHandler{ "setKeyboardLayout": {Func: rpcSetKeyboardLayout, Params: []string{"layout"}}, "getKeyboardMacros": {Func: getKeyboardMacros}, "setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}}, + "getLocalLoopbackOnly": {Func: rpcGetLocalLoopbackOnly}, + "setLocalLoopbackOnly": {Func: rpcSetLocalLoopbackOnly, Params: []string{"enabled"}}, } diff --git a/ui/src/components/ConfirmDialog.tsx b/ui/src/components/ConfirmDialog.tsx index 3771096..f6a3923 100644 --- a/ui/src/components/ConfirmDialog.tsx +++ b/ui/src/components/ConfirmDialog.tsx @@ -1,12 +1,12 @@ import { - ExclamationTriangleIcon, CheckCircleIcon, + ExclamationTriangleIcon, InformationCircleIcon, } from "@heroicons/react/24/outline"; -import { cx } from "@/cva.config"; import { Button } from "@/components/Button"; import Modal from "@/components/Modal"; +import { cx } from "@/cva.config"; type Variant = "danger" | "success" | "warning" | "info"; @@ -14,7 +14,7 @@ interface ConfirmDialogProps { open: boolean; onClose: () => void; title: string; - description: string; + description: React.ReactNode; variant?: Variant; confirmText?: string; cancelText?: string | null; @@ -84,8 +84,8 @@ export function ConfirmDialog({ >