mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-15 17:52:47 +02:00
Update configuration options for client UI (#2139)
* Add additional configuration options to client UI * add quick settings options * Remove unused UI elements and client options * Add additional config properties to daemon protocol This update extends the daemon protocol to include new configuration properties: interfaceName, wireguardPort, disableAutoConnect, serverSSHAllowed, rosenpassEnabled, and rosenpassPermissive. * Refactor UI client settings and restart process * Fix disable connect option while connecting
This commit is contained in:
@ -5,6 +5,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -125,44 +126,55 @@ type serviceClient struct {
|
||||
icUpdateCloud []byte
|
||||
|
||||
// systray menu items
|
||||
mStatus *systray.MenuItem
|
||||
mUp *systray.MenuItem
|
||||
mDown *systray.MenuItem
|
||||
mAdminPanel *systray.MenuItem
|
||||
mSettings *systray.MenuItem
|
||||
mAbout *systray.MenuItem
|
||||
mVersionUI *systray.MenuItem
|
||||
mVersionDaemon *systray.MenuItem
|
||||
mUpdate *systray.MenuItem
|
||||
mQuit *systray.MenuItem
|
||||
mRoutes *systray.MenuItem
|
||||
mStatus *systray.MenuItem
|
||||
mUp *systray.MenuItem
|
||||
mDown *systray.MenuItem
|
||||
mAdminPanel *systray.MenuItem
|
||||
mSettings *systray.MenuItem
|
||||
mAbout *systray.MenuItem
|
||||
mVersionUI *systray.MenuItem
|
||||
mVersionDaemon *systray.MenuItem
|
||||
mUpdate *systray.MenuItem
|
||||
mQuit *systray.MenuItem
|
||||
mRoutes *systray.MenuItem
|
||||
mAllowSSH *systray.MenuItem
|
||||
mAutoConnect *systray.MenuItem
|
||||
mEnableRosenpass *systray.MenuItem
|
||||
mAdvancedSettings *systray.MenuItem
|
||||
|
||||
// application with main windows.
|
||||
app fyne.App
|
||||
wSettings fyne.Window
|
||||
showSettings bool
|
||||
sendNotification bool
|
||||
app fyne.App
|
||||
wSettings fyne.Window
|
||||
showAdvancedSettings bool
|
||||
sendNotification bool
|
||||
|
||||
// input elements for settings form
|
||||
iMngURL *widget.Entry
|
||||
iAdminURL *widget.Entry
|
||||
iConfigFile *widget.Entry
|
||||
iLogFile *widget.Entry
|
||||
iPreSharedKey *widget.Entry
|
||||
iMngURL *widget.Entry
|
||||
iAdminURL *widget.Entry
|
||||
iConfigFile *widget.Entry
|
||||
iLogFile *widget.Entry
|
||||
iPreSharedKey *widget.Entry
|
||||
iInterfaceName *widget.Entry
|
||||
iInterfacePort *widget.Entry
|
||||
|
||||
// switch elements for settings form
|
||||
sRosenpassPermissive *widget.Check
|
||||
|
||||
// observable settings over corresponding iMngURL and iPreSharedKey values.
|
||||
managementURL string
|
||||
preSharedKey string
|
||||
adminURL string
|
||||
managementURL string
|
||||
preSharedKey string
|
||||
adminURL string
|
||||
RosenpassPermissive bool
|
||||
interfaceName string
|
||||
interfacePort int
|
||||
|
||||
connected bool
|
||||
update *version.Update
|
||||
daemonVersion string
|
||||
updateIndicationLock sync.Mutex
|
||||
isUpdateIconActive bool
|
||||
|
||||
showRoutes bool
|
||||
wRoutes fyne.Window
|
||||
showRoutes bool
|
||||
wRoutes fyne.Window
|
||||
}
|
||||
|
||||
// newServiceClient instance constructor
|
||||
@ -175,9 +187,9 @@ func newServiceClient(addr string, a fyne.App, showSettings bool, showRoutes boo
|
||||
app: a,
|
||||
sendNotification: false,
|
||||
|
||||
showSettings: showSettings,
|
||||
showRoutes: showRoutes,
|
||||
update: version.NewUpdate(),
|
||||
showAdvancedSettings: showSettings,
|
||||
showRoutes: showRoutes,
|
||||
update: version.NewUpdate(),
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
@ -215,8 +227,13 @@ func (s *serviceClient) showSettingsUI() {
|
||||
s.iLogFile = widget.NewEntry()
|
||||
s.iLogFile.Disable()
|
||||
s.iPreSharedKey = widget.NewPasswordEntry()
|
||||
s.iInterfaceName = widget.NewEntry()
|
||||
s.iInterfacePort = widget.NewEntry()
|
||||
s.sRosenpassPermissive = widget.NewCheck("Enable Rosenpass permissive mode", nil)
|
||||
|
||||
s.wSettings.SetContent(s.getSettingsForm())
|
||||
s.wSettings.Resize(fyne.NewSize(600, 100))
|
||||
s.wSettings.Resize(fyne.NewSize(600, 400))
|
||||
s.wSettings.SetFixedSize(true)
|
||||
|
||||
s.getSrvConfig()
|
||||
|
||||
@ -239,6 +256,9 @@ func showErrorMSG(msg string) {
|
||||
func (s *serviceClient) getSettingsForm() *widget.Form {
|
||||
return &widget.Form{
|
||||
Items: []*widget.FormItem{
|
||||
{Text: "Quantum-Resistance", Widget: s.sRosenpassPermissive},
|
||||
{Text: "Interface Name", Widget: s.iInterfaceName},
|
||||
{Text: "Interface Port", Widget: s.iInterfacePort},
|
||||
{Text: "Management URL", Widget: s.iMngURL},
|
||||
{Text: "Admin URL", Widget: s.iAdminURL},
|
||||
{Text: "Pre-shared Key", Widget: s.iPreSharedKey},
|
||||
@ -255,45 +275,42 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
||||
}
|
||||
}
|
||||
|
||||
port, err := strconv.ParseInt(s.iInterfacePort.Text, 10, 64)
|
||||
if err != nil {
|
||||
dialog.ShowError(errors.New("Invalid interface port"), s.wSettings)
|
||||
return
|
||||
}
|
||||
|
||||
defer s.wSettings.Close()
|
||||
// if management URL or Pre-shared key changed, we try to re-login with new settings.
|
||||
|
||||
// If the management URL, pre-shared key, admin URL, Rosenpass permissive mode,
|
||||
// interface name, or interface port have changed, we attempt to re-login with the new settings.
|
||||
if s.managementURL != s.iMngURL.Text || s.preSharedKey != s.iPreSharedKey.Text ||
|
||||
s.adminURL != s.iAdminURL.Text {
|
||||
s.adminURL != s.iAdminURL.Text || s.RosenpassPermissive != s.sRosenpassPermissive.Checked ||
|
||||
s.interfaceName != s.iInterfaceName.Text || s.interfacePort != int(port) {
|
||||
|
||||
s.managementURL = s.iMngURL.Text
|
||||
s.preSharedKey = s.iPreSharedKey.Text
|
||||
s.adminURL = s.iAdminURL.Text
|
||||
|
||||
client, err := s.getSrvClient(failFastTimeout)
|
||||
if err != nil {
|
||||
log.Errorf("get daemon client: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
loginRequest := proto.LoginRequest{
|
||||
ManagementUrl: s.iMngURL.Text,
|
||||
AdminURL: s.iAdminURL.Text,
|
||||
IsLinuxDesktopClient: runtime.GOOS == "linux",
|
||||
RosenpassPermissive: &s.sRosenpassPermissive.Checked,
|
||||
InterfaceName: &s.iInterfaceName.Text,
|
||||
WireguardPort: &port,
|
||||
}
|
||||
|
||||
if s.iPreSharedKey.Text != "**********" {
|
||||
loginRequest.OptionalPreSharedKey = &s.iPreSharedKey.Text
|
||||
}
|
||||
|
||||
_, err = client.Login(s.ctx, &loginRequest)
|
||||
if err != nil {
|
||||
log.Errorf("login to management URL: %v", err)
|
||||
if err := s.restartClient(&loginRequest); err != nil {
|
||||
log.Errorf("restarting client connection: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = client.Up(s.ctx, &proto.UpRequest{})
|
||||
if err != nil {
|
||||
log.Errorf("login to management URL: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
s.wSettings.Close()
|
||||
},
|
||||
OnCancel: func() {
|
||||
s.wSettings.Close()
|
||||
@ -499,7 +516,14 @@ func (s *serviceClient) onTrayReady() {
|
||||
s.mDown.Disable()
|
||||
s.mAdminPanel = systray.AddMenuItem("Admin Panel", "Netbird Admin Panel")
|
||||
systray.AddSeparator()
|
||||
|
||||
s.mSettings = systray.AddMenuItem("Settings", "Settings of the application")
|
||||
s.mAllowSSH = s.mSettings.AddSubMenuItemCheckbox("Allow SSH", "Allow SSH connections", false)
|
||||
s.mAutoConnect = s.mSettings.AddSubMenuItemCheckbox("Connect on Startup", "Connect automatically when the service starts", false)
|
||||
s.mEnableRosenpass = s.mSettings.AddSubMenuItemCheckbox("Enable Quantum-Resistance", "Enable post-quantum security via Rosenpass", false)
|
||||
s.mAdvancedSettings = s.mSettings.AddSubMenuItem("Advanced Settings", "Advanced settings of the application")
|
||||
s.loadSettings()
|
||||
|
||||
s.mRoutes = systray.AddMenuItem("Network Routes", "Open the routes management window")
|
||||
s.mRoutes.Disable()
|
||||
systray.AddSeparator()
|
||||
@ -539,7 +563,7 @@ func (s *serviceClient) onTrayReady() {
|
||||
case <-s.mAdminPanel.ClickedCh:
|
||||
err = open.Run(s.adminURL)
|
||||
case <-s.mUp.ClickedCh:
|
||||
s.mUp.Disabled()
|
||||
s.mUp.Disable()
|
||||
go func() {
|
||||
defer s.mUp.Enable()
|
||||
err := s.menuUpClick()
|
||||
@ -558,10 +582,40 @@ func (s *serviceClient) onTrayReady() {
|
||||
return
|
||||
}
|
||||
}()
|
||||
case <-s.mSettings.ClickedCh:
|
||||
s.mSettings.Disable()
|
||||
case <-s.mAllowSSH.ClickedCh:
|
||||
if s.mAllowSSH.Checked() {
|
||||
s.mAllowSSH.Uncheck()
|
||||
} else {
|
||||
s.mAllowSSH.Check()
|
||||
}
|
||||
if err := s.updateConfig(); err != nil {
|
||||
log.Errorf("failed to update config: %v", err)
|
||||
return
|
||||
}
|
||||
case <-s.mAutoConnect.ClickedCh:
|
||||
if s.mAutoConnect.Checked() {
|
||||
s.mAutoConnect.Uncheck()
|
||||
} else {
|
||||
s.mAutoConnect.Check()
|
||||
}
|
||||
if err := s.updateConfig(); err != nil {
|
||||
log.Errorf("failed to update config: %v", err)
|
||||
return
|
||||
}
|
||||
case <-s.mEnableRosenpass.ClickedCh:
|
||||
if s.mEnableRosenpass.Checked() {
|
||||
s.mEnableRosenpass.Uncheck()
|
||||
} else {
|
||||
s.mEnableRosenpass.Check()
|
||||
}
|
||||
if err := s.updateConfig(); err != nil {
|
||||
log.Errorf("failed to update config: %v", err)
|
||||
return
|
||||
}
|
||||
case <-s.mAdvancedSettings.ClickedCh:
|
||||
s.mAdvancedSettings.Disable()
|
||||
go func() {
|
||||
defer s.mSettings.Enable()
|
||||
defer s.mAdvancedSettings.Enable()
|
||||
defer s.getSrvConfig()
|
||||
s.runSelfCommand("settings", "true")
|
||||
}()
|
||||
@ -663,13 +717,23 @@ func (s *serviceClient) getSrvConfig() {
|
||||
s.adminURL = cfg.AdminURL
|
||||
}
|
||||
s.preSharedKey = cfg.PreSharedKey
|
||||
s.RosenpassPermissive = cfg.RosenpassPermissive
|
||||
s.interfaceName = cfg.InterfaceName
|
||||
s.interfacePort = int(cfg.WireguardPort)
|
||||
|
||||
if s.showSettings {
|
||||
if s.showAdvancedSettings {
|
||||
s.iMngURL.SetText(s.managementURL)
|
||||
s.iAdminURL.SetText(s.adminURL)
|
||||
s.iConfigFile.SetText(cfg.ConfigFile)
|
||||
s.iLogFile.SetText(cfg.LogFile)
|
||||
s.iPreSharedKey.SetText(cfg.PreSharedKey)
|
||||
s.iInterfaceName.SetText(cfg.InterfaceName)
|
||||
s.iInterfacePort.SetText(strconv.Itoa(int(cfg.WireguardPort)))
|
||||
s.sRosenpassPermissive.SetChecked(cfg.RosenpassPermissive)
|
||||
if !cfg.RosenpassEnabled {
|
||||
s.sRosenpassPermissive.Disable()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -704,6 +768,81 @@ func (s *serviceClient) onSessionExpire() {
|
||||
}
|
||||
}
|
||||
|
||||
// loadSettings loads the settings from the config file and updates the UI elements accordingly.
|
||||
func (s *serviceClient) loadSettings() {
|
||||
conn, err := s.getSrvClient(failFastTimeout)
|
||||
if err != nil {
|
||||
log.Errorf("get client: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := conn.GetConfig(s.ctx, &proto.GetConfigRequest{})
|
||||
if err != nil {
|
||||
log.Errorf("get config settings from server: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.ServerSSHAllowed {
|
||||
s.mAllowSSH.Check()
|
||||
} else {
|
||||
s.mAllowSSH.Uncheck()
|
||||
}
|
||||
|
||||
if cfg.DisableAutoConnect {
|
||||
s.mAutoConnect.Uncheck()
|
||||
} else {
|
||||
s.mAutoConnect.Check()
|
||||
}
|
||||
|
||||
if cfg.RosenpassEnabled {
|
||||
s.mEnableRosenpass.Check()
|
||||
} else {
|
||||
s.mEnableRosenpass.Uncheck()
|
||||
}
|
||||
}
|
||||
|
||||
// updateConfig updates the configuration parameters
|
||||
// based on the values selected in the settings window.
|
||||
func (s *serviceClient) updateConfig() error {
|
||||
disableAutoStart := !s.mAutoConnect.Checked()
|
||||
sshAllowed := s.mAllowSSH.Checked()
|
||||
rosenpassEnabled := s.mEnableRosenpass.Checked()
|
||||
|
||||
loginRequest := proto.LoginRequest{
|
||||
IsLinuxDesktopClient: runtime.GOOS == "linux",
|
||||
ServerSSHAllowed: &sshAllowed,
|
||||
RosenpassEnabled: &rosenpassEnabled,
|
||||
DisableAutoConnect: &disableAutoStart,
|
||||
}
|
||||
|
||||
if err := s.restartClient(&loginRequest); err != nil {
|
||||
log.Errorf("restarting client connection: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// restartClient restarts the client connection.
|
||||
func (s *serviceClient) restartClient(loginRequest *proto.LoginRequest) error {
|
||||
client, err := s.getSrvClient(failFastTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.Login(s.ctx, loginRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.Up(s.ctx, &proto.UpRequest{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func openURL(url string) error {
|
||||
var err error
|
||||
switch runtime.GOOS {
|
||||
|
Reference in New Issue
Block a user