From a77fa0055b17695c71b0d2d2f0e9ef5ac74de1a5 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Wed, 28 Feb 2024 16:48:13 +0300 Subject: [PATCH 01/12] Add session expiration notification --- client/ui/client_ui.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index a1682bd4c94..01bc8022aac 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -630,6 +630,15 @@ func (s *serviceClient) onUpdateAvailable() { } } +func (s *serviceClient) onSessionEnd() { + s.app.SendNotification( + fyne.NewNotification( + "Peer Session Expired", + "Please re-authenticate to connect to the network", + ), + ) +} + func openURL(url string) error { var err error switch runtime.GOOS { From 6130ba085b9ee31e1449a5b9a68ed553858a43d2 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 10:09:43 +0300 Subject: [PATCH 02/12] Integrate SessionWatcher into the client UI and add a notification system for session expiration. --- client/ui/client_ui.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 01bc8022aac..3901d4e0317 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -145,9 +145,11 @@ type serviceClient struct { managementURL string preSharedKey string adminURL string + configFile string connected bool update *version.Update + sessionWatcher *internal.SessionWatcher daemonVersion string updateIndicationLock sync.Mutex isUpdateIconActive bool @@ -166,6 +168,13 @@ func newServiceClient(addr string, a fyne.App, showSettings bool) *serviceClient update: version.NewUpdate(), } + //s.getSrvConfig() + //sessionWatcher, err := internal.NewSessionWatcher(s.ctx, s.configFile) + //if err == nil { + // s.sessionWatcher = sessionWatcher + // s.sessionWatcher.SetOnExpireListener(s.onSessionExpire) + //} + if runtime.GOOS == "windows" { s.icConnected = iconConnectedICO s.icDisconnected = iconDisconnectedICO @@ -546,6 +555,15 @@ func (s *serviceClient) onTrayReady() { } } }() + + s.getSrvConfig() + sessionWatcher, err := internal.NewSessionWatcher(s.ctx, s.configFile) + if err != nil { + log.Errorf("session watcher: %v", err) + return + } + sessionWatcher.SetOnExpireListener(s.onSessionExpire) + s.sessionWatcher = sessionWatcher } func normalizedVersion(version string) string { @@ -606,6 +624,7 @@ func (s *serviceClient) getSrvConfig() { s.adminURL = cfg.AdminURL } s.preSharedKey = cfg.PreSharedKey + s.configFile = cfg.ConfigFile if s.showSettings { s.iMngURL.SetText(s.managementURL) @@ -630,7 +649,7 @@ func (s *serviceClient) onUpdateAvailable() { } } -func (s *serviceClient) onSessionEnd() { +func (s *serviceClient) onSessionExpire() { s.app.SendNotification( fyne.NewNotification( "Peer Session Expired", From 98f9a212f7e9dc8165b159a434467b7d394dee2d Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 10:10:09 +0300 Subject: [PATCH 03/12] Add SessionWatcher to manage and check session status. This update introduces a new SessionWatcher in the internal package of the client UI. The purpose of SessionWatcher is to periodically check the login status, and in case the session expires, it triggers a predefined onExpireListener function. An appropriate listener can be set to notify the user about session expiration. --- client/internal/session.go | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 client/internal/session.go diff --git a/client/internal/session.go b/client/internal/session.go new file mode 100644 index 00000000000..8e245337ac2 --- /dev/null +++ b/client/internal/session.go @@ -0,0 +1,62 @@ +package internal + +import ( + "context" + "net/url" + "time" +) + +type SessionWatcher struct { + ctx context.Context + privateKey string + mgmURL *url.URL + sshKey string + + fetchTicker *time.Ticker + + onExpireListener func() +} + +func NewSessionWatcher(ctx context.Context, configPath string) (*SessionWatcher, error) { + cfg, err := ReadConfig(configPath) + if err != nil { + return nil, err + } + + s := &SessionWatcher{ + ctx: ctx, + privateKey: cfg.PrivateKey, + mgmURL: cfg.ManagementURL, + sshKey: cfg.SSHKey, + fetchTicker: time.NewTicker(10 * time.Second), + } + go s.startFetcher() + return s, nil +} + +func (s *SessionWatcher) SetOnExpireListener(onExpire func()) { + s.onExpireListener = onExpire +} + +func (s *SessionWatcher) startFetcher() { + required, _ := IsLoginRequired(s.ctx, s.privateKey, s.mgmURL, s.sshKey) + if required { + if s.onExpireListener != nil { + s.onExpireListener() + } + } + + for { + select { + case <-s.fetchTicker.C: + required, _ := IsLoginRequired(s.ctx, s.privateKey, s.mgmURL, s.sshKey) + if required { + if s.onExpireListener != nil { + s.onExpireListener() + } + } + } + } +} + +func (s *SessionWatcher) StopWatch() { s.fetchTicker.Stop() } From 03f2246541567a312ab34a0f1b1dae6adf30690a Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 12:28:09 +0300 Subject: [PATCH 04/12] Refactor fetchTicker as watchTicker and add SessionWatcher --- client/internal/session.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/client/internal/session.go b/client/internal/session.go index 8e245337ac2..6a58290adb9 100644 --- a/client/internal/session.go +++ b/client/internal/session.go @@ -12,11 +12,12 @@ type SessionWatcher struct { mgmURL *url.URL sshKey string - fetchTicker *time.Ticker + watchTicker *time.Ticker onExpireListener func() } +// NewSessionWatcher creates a new instance of SessionWatcher. func NewSessionWatcher(ctx context.Context, configPath string) (*SessionWatcher, error) { cfg, err := ReadConfig(configPath) if err != nil { @@ -28,17 +29,21 @@ func NewSessionWatcher(ctx context.Context, configPath string) (*SessionWatcher, privateKey: cfg.PrivateKey, mgmURL: cfg.ManagementURL, sshKey: cfg.SSHKey, - fetchTicker: time.NewTicker(10 * time.Second), + watchTicker: time.NewTicker(10 * time.Second), } - go s.startFetcher() + go s.startWatcher() return s, nil } +// SetOnExpireListener sets the callback func to be called when the session expires. func (s *SessionWatcher) SetOnExpireListener(onExpire func()) { s.onExpireListener = onExpire } -func (s *SessionWatcher) startFetcher() { +// startWatcher starts the session watcher. +// It checks if login is required, +// if login is required and onExpireListener is set, it calls the onExpireListener. +func (s *SessionWatcher) startWatcher() { required, _ := IsLoginRequired(s.ctx, s.privateKey, s.mgmURL, s.sshKey) if required { if s.onExpireListener != nil { @@ -48,7 +53,7 @@ func (s *SessionWatcher) startFetcher() { for { select { - case <-s.fetchTicker.C: + case <-s.watchTicker.C: required, _ := IsLoginRequired(s.ctx, s.privateKey, s.mgmURL, s.sshKey) if required { if s.onExpireListener != nil { @@ -59,4 +64,6 @@ func (s *SessionWatcher) startFetcher() { } } -func (s *SessionWatcher) StopWatch() { s.fetchTicker.Stop() } +// StopWatch stops the watch ticker of the SessionWatcher, +// effectively stopping the session watching a process. +func (s *SessionWatcher) StopWatch() { s.watchTicker.Stop() } From b4c26340ef2d64dc0a3a4c723c0b5e948334eca9 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 16:14:37 +0300 Subject: [PATCH 05/12] Implement session expiry notifications --- client/ui/client_ui.go | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 3901d4e0317..1b6d11e4efd 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -130,9 +130,10 @@ type serviceClient struct { mQuit *systray.MenuItem // application with main windows. - app fyne.App - wSettings fyne.Window - showSettings bool + app fyne.App + wSettings fyne.Window + showSettings bool + sendNotification bool // input elements for settings form iMngURL *widget.Entry @@ -145,11 +146,9 @@ type serviceClient struct { managementURL string preSharedKey string adminURL string - configFile string connected bool update *version.Update - sessionWatcher *internal.SessionWatcher daemonVersion string updateIndicationLock sync.Mutex isUpdateIconActive bool @@ -160,9 +159,10 @@ type serviceClient struct { // This constructor also builds the UI elements for the settings window. func newServiceClient(addr string, a fyne.App, showSettings bool) *serviceClient { s := &serviceClient{ - ctx: context.Background(), - addr: addr, - app: a, + ctx: context.Background(), + addr: addr, + app: a, + sendNotification: true, showSettings: showSettings, update: version.NewUpdate(), @@ -386,9 +386,15 @@ func (s *serviceClient) updateStatus() error { s.updateIndicationLock.Lock() defer s.updateIndicationLock.Unlock() + // notify the user when the session has expired + if status.Status == string(internal.StatusNeedsLogin) { + s.onSessionExpire() + } + var systrayIconState bool if status.Status == string(internal.StatusConnected) && !s.mUp.Disabled() { s.connected = true + s.sendNotification = true if s.isUpdateIconActive { systray.SetIcon(s.icUpdateConnected) } else { @@ -555,15 +561,6 @@ func (s *serviceClient) onTrayReady() { } } }() - - s.getSrvConfig() - sessionWatcher, err := internal.NewSessionWatcher(s.ctx, s.configFile) - if err != nil { - log.Errorf("session watcher: %v", err) - return - } - sessionWatcher.SetOnExpireListener(s.onSessionExpire) - s.sessionWatcher = sessionWatcher } func normalizedVersion(version string) string { @@ -624,7 +621,6 @@ func (s *serviceClient) getSrvConfig() { s.adminURL = cfg.AdminURL } s.preSharedKey = cfg.PreSharedKey - s.configFile = cfg.ConfigFile if s.showSettings { s.iMngURL.SetText(s.managementURL) @@ -649,13 +645,17 @@ func (s *serviceClient) onUpdateAvailable() { } } +// onSessionExpire sends a notification to the user when the session expires. func (s *serviceClient) onSessionExpire() { - s.app.SendNotification( - fyne.NewNotification( - "Peer Session Expired", - "Please re-authenticate to connect to the network", - ), - ) + if s.sendNotification { + s.app.SendNotification( + fyne.NewNotification( + "Peer Session Expired", + "Please re-authenticate to connect to the network", + ), + ) + s.sendNotification = false + } } func openURL(url string) error { From 7911f150f9a684eafba7a7c0a1db75925d081f86 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 16:16:17 +0300 Subject: [PATCH 06/12] Remove SessionWatcher --- client/internal/session.go | 69 -------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 client/internal/session.go diff --git a/client/internal/session.go b/client/internal/session.go deleted file mode 100644 index 6a58290adb9..00000000000 --- a/client/internal/session.go +++ /dev/null @@ -1,69 +0,0 @@ -package internal - -import ( - "context" - "net/url" - "time" -) - -type SessionWatcher struct { - ctx context.Context - privateKey string - mgmURL *url.URL - sshKey string - - watchTicker *time.Ticker - - onExpireListener func() -} - -// NewSessionWatcher creates a new instance of SessionWatcher. -func NewSessionWatcher(ctx context.Context, configPath string) (*SessionWatcher, error) { - cfg, err := ReadConfig(configPath) - if err != nil { - return nil, err - } - - s := &SessionWatcher{ - ctx: ctx, - privateKey: cfg.PrivateKey, - mgmURL: cfg.ManagementURL, - sshKey: cfg.SSHKey, - watchTicker: time.NewTicker(10 * time.Second), - } - go s.startWatcher() - return s, nil -} - -// SetOnExpireListener sets the callback func to be called when the session expires. -func (s *SessionWatcher) SetOnExpireListener(onExpire func()) { - s.onExpireListener = onExpire -} - -// startWatcher starts the session watcher. -// It checks if login is required, -// if login is required and onExpireListener is set, it calls the onExpireListener. -func (s *SessionWatcher) startWatcher() { - required, _ := IsLoginRequired(s.ctx, s.privateKey, s.mgmURL, s.sshKey) - if required { - if s.onExpireListener != nil { - s.onExpireListener() - } - } - - for { - select { - case <-s.watchTicker.C: - required, _ := IsLoginRequired(s.ctx, s.privateKey, s.mgmURL, s.sshKey) - if required { - if s.onExpireListener != nil { - s.onExpireListener() - } - } - } - } -} - -// StopWatch stops the watch ticker of the SessionWatcher, -// effectively stopping the session watching a process. -func (s *SessionWatcher) StopWatch() { s.watchTicker.Stop() } From 99196dfae5414952ca777a2a27567102d2fad1bc Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 16:17:51 +0300 Subject: [PATCH 07/12] cleanup --- client/ui/client_ui.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 1b6d11e4efd..0a5366e6328 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -168,13 +168,6 @@ func newServiceClient(addr string, a fyne.App, showSettings bool) *serviceClient update: version.NewUpdate(), } - //s.getSrvConfig() - //sessionWatcher, err := internal.NewSessionWatcher(s.ctx, s.configFile) - //if err == nil { - // s.sessionWatcher = sessionWatcher - // s.sessionWatcher.SetOnExpireListener(s.onSessionExpire) - //} - if runtime.GOOS == "windows" { s.icConnected = iconConnectedICO s.icDisconnected = iconDisconnectedICO From f75e3ba3af3b3e4a97613386982cc7b2b4be4deb Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Thu, 29 Feb 2024 18:34:12 +0300 Subject: [PATCH 08/12] Set application ID during instantiation --- client/ui/client_ui.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 0a5366e6328..0fbbf4bf496 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -61,7 +61,7 @@ func main() { flag.Parse() - a := app.New() + a := app.NewWithID("Netbird") a.SetIcon(fyne.NewStaticResource("netbird", iconDisconnectedPNG)) client := newServiceClient(daemonAddr, a, showSettings) From dd0837f64072e74336fe998e269cdc91116eb39f Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Fri, 1 Mar 2024 11:23:48 +0300 Subject: [PATCH 09/12] Send expiry notification when the client was already connected --- client/ui/client_ui.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 0fbbf4bf496..57dd23ba5a0 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -162,7 +162,7 @@ func newServiceClient(addr string, a fyne.App, showSettings bool) *serviceClient ctx: context.Background(), addr: addr, app: a, - sendNotification: true, + sendNotification: false, showSettings: showSettings, update: version.NewUpdate(), From 77095f06daf9f24e46063b92a282879c16134853 Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Fri, 1 Mar 2024 17:04:33 +0100 Subject: [PATCH 10/12] update text --- client/ui/client_ui.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 57dd23ba5a0..324b03f40ea 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -643,7 +643,7 @@ func (s *serviceClient) onSessionExpire() { if s.sendNotification { s.app.SendNotification( fyne.NewNotification( - "Peer Session Expired", + "NetBird session expired", "Please re-authenticate to connect to the network", ), ) From c3217c78d038baddd56050e727d640e713c2a89d Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Fri, 1 Mar 2024 17:18:55 +0100 Subject: [PATCH 11/12] update title text --- client/ui/client_ui.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index 324b03f40ea..c0c83e80dd5 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -641,9 +641,13 @@ func (s *serviceClient) onUpdateAvailable() { // onSessionExpire sends a notification to the user when the session expires. func (s *serviceClient) onSessionExpire() { if s.sendNotification { + title := "Connection session expired" + if runtime.GOOS == "darwin" { + title = "NetBird connection session expired" + } s.app.SendNotification( fyne.NewNotification( - "NetBird session expired", + title, "Please re-authenticate to connect to the network", ), ) From dd754a55b81f550798ad94433c9cff7cd37346cf Mon Sep 17 00:00:00 2001 From: Bethuel Mmbaga Date: Fri, 1 Mar 2024 19:39:36 +0300 Subject: [PATCH 12/12] update notifaction window title --- client/ui/client_ui.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go index c0c83e80dd5..e242a26db66 100644 --- a/client/ui/client_ui.go +++ b/client/ui/client_ui.go @@ -61,7 +61,7 @@ func main() { flag.Parse() - a := app.NewWithID("Netbird") + a := app.NewWithID("NetBird") a.SetIcon(fyne.NewStaticResource("netbird", iconDisconnectedPNG)) client := newServiceClient(daemonAddr, a, showSettings)