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.
This commit is contained in:
Alex Goodkind 2025-05-22 18:10:02 -07:00
parent c1d771cced
commit 15f5a25f23
No known key found for this signature in database
3 changed files with 165 additions and 117 deletions

View File

@ -95,6 +95,7 @@ type Config struct {
DisplayDimAfterSec int `json:"display_dim_after_sec"`
DisplayOffAfterSec int `json:"display_off_after_sec"`
TLSMode string `json:"tls_mode"` // options: "self-signed", "user-defined", ""
LocalWebServerLoopbackOnly bool `json:"local_web_server_loopback_only"`
UsbConfig *usbgadget.Config `json:"usb_config"`
UsbDevices *usbgadget.Devices `json:"usb_devices"`
NetworkConfig *network.NetworkConfig `json:"network_config"`
@ -115,6 +116,7 @@ var defaultConfig = &Config{
DisplayDimAfterSec: 120, // 2 minutes
DisplayOffAfterSec: 1800, // 30 minutes
TLSMode: "",
LocalWebServerLoopbackOnly: false, // Allow access from any network interface by default
UsbConfig: &usbgadget.Config{
VendorId: "0x1d6b", //The Linux Foundation
ProductId: "0x0104", //Multifunction Composite Gadget

View File

@ -1006,6 +1006,40 @@ func setKeyboardMacros(params KeyboardMacrosParams) (interface{}, error) {
return nil, nil
}
func rpcGetLocalWebServerLoopbackOnly() (bool, error) {
return config.LocalWebServerLoopbackOnly, nil
}
func rpcSetLocalWebServerLoopbackOnly(enabled bool) error {
// Check if the setting is actually changing
if config.LocalWebServerLoopbackOnly == enabled {
return nil
}
// Update the setting
config.LocalWebServerLoopbackOnly = enabled
if err := SaveConfig(); err != nil {
return fmt.Errorf("failed to save config: %w", err)
}
// Log the change
if enabled {
logger.Info().Msg("Web server now set to only listen on loopback interface, this will take effect after reboot")
} else {
logger.Info().Msg("Web server now set to listen on all interfaces, this will take effect after reboot")
}
// Return a message that changes require a reboot
message := "Web server binding changed. You must reboot the device for this change to take effect."
if enabled {
message = "Web server set to loopback-only mode. After reboot, the web interface will only be accessible from the device itself. You must reboot the device for this change to take effect."
} else {
message = "Web server set to listen on all interfaces. After reboot, the web interface will be accessible from other devices on the network. You must reboot the device for this change to take effect."
}
return fmt.Errorf(message)
}
var rpcHandlers = map[string]RPCHandler{
"ping": {Func: rpcPing},
"reboot": {Func: rpcReboot, Params: []string{"force"}},
@ -1083,4 +1117,6 @@ var rpcHandlers = map[string]RPCHandler{
"setKeyboardLayout": {Func: rpcSetKeyboardLayout, Params: []string{"layout"}},
"getKeyboardMacros": {Func: getKeyboardMacros},
"setKeyboardMacros": {Func: setKeyboardMacros, Params: []string{"params"}},
"getLocalWebServerLoopbackOnly": {Func: rpcGetLocalWebServerLoopbackOnly},
"setLocalWebServerLoopbackOnly": {Func: rpcSetLocalWebServerLoopbackOnly, Params: []string{"enabled"}},
}

12
web.go
View File

@ -54,6 +54,7 @@ type ChangePasswordRequest struct {
type LocalDevice struct {
AuthMode *string `json:"authMode"`
DeviceID string `json:"deviceId"`
LocalWebServerLoopbackOnly bool `json:"localWebServerLoopbackOnly"`
}
type DeviceStatus struct {
@ -532,7 +533,15 @@ func basicAuthProtectedMiddleware(requireDeveloperMode bool) gin.HandlerFunc {
func RunWebServer() {
r := setupRouter()
err := r.Run(":80")
// Determine the binding address based on the config
bindAddress := ":80" // Default to all interfaces
if config.LocalWebServerLoopbackOnly {
bindAddress = "localhost:80" // Loopback only (both IPv4 and IPv6)
}
logger.Info().Str("bindAddress", bindAddress).Bool("loopbackOnly", config.LocalWebServerLoopbackOnly).Msg("Starting web server")
err := r.Run(bindAddress)
if err != nil {
panic(err)
}
@ -542,6 +551,7 @@ func handleDevice(c *gin.Context) {
response := LocalDevice{
AuthMode: &config.LocalAuthMode,
DeviceID: GetDeviceID(),
LocalWebServerLoopbackOnly: config.LocalWebServerLoopbackOnly,
}
c.JSON(http.StatusOK, response)