Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion client/installer.nsis
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ Pop $0
!macroend

Function .onInit
SetRegView 64
StrCpy $INSTDIR "${INSTALL_DIR}"
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$(^NAME)" "UninstallString"
${If} $R0 != ""
Expand All @@ -214,6 +215,10 @@ ${If} $R0 != ""

${EndIf}
FunctionEnd

Function un.onInit
SetRegView 64
FunctionEnd
######################################################################
Section -MainProgram
${INSTALL_TYPE}
Expand All @@ -228,6 +233,7 @@ Section -MainProgram
!else
File /r "..\\dist\\netbird_windows_amd64\\"
!endif
File "..\\client\\ui\\assets\\netbird.png"
Comment thread
lixmal marked this conversation as resolved.
SectionEnd
######################################################################

Expand All @@ -247,9 +253,11 @@ WriteRegStr ${REG_ROOT} "${UI_REG_APP_PATH}" "" "$INSTDIR\${UI_APP_EXE}"
; Create autostart registry entry based on checkbox
DetailPrint "Autostart enabled: $AutostartEnabled"
${If} $AutostartEnabled == "1"
WriteRegStr HKCU "${AUTOSTART_REG_KEY}" "${APP_NAME}" "$INSTDIR\${UI_APP_EXE}.exe"
WriteRegStr HKLM "${AUTOSTART_REG_KEY}" "${APP_NAME}" '"$INSTDIR\${UI_APP_EXE}.exe"'
DetailPrint "Added autostart registry entry: $INSTDIR\${UI_APP_EXE}.exe"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
${Else}
DeleteRegValue HKLM "${AUTOSTART_REG_KEY}" "${APP_NAME}"
; Legacy: pre-HKLM installs wrote to HKCU; clean that up too.
DeleteRegValue HKCU "${AUTOSTART_REG_KEY}" "${APP_NAME}"
DetailPrint "Autostart not enabled by user"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
${EndIf}
Expand Down Expand Up @@ -283,6 +291,8 @@ ExecWait `taskkill /im ${UI_APP_EXE}.exe /f`

; Remove autostart registry entry
DetailPrint "Removing autostart registry entry if exists..."
DeleteRegValue HKLM "${AUTOSTART_REG_KEY}" "${APP_NAME}"
; Legacy: pre-HKLM installs wrote to HKCU; clean that up too.
DeleteRegValue HKCU "${AUTOSTART_REG_KEY}" "${APP_NAME}"

; Handle data deletion based on checkbox
Expand Down Expand Up @@ -321,6 +331,7 @@ DetailPrint "Removing registry keys..."
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
DeleteRegKey ${REG_ROOT} "${UI_REG_APP_PATH}"
DeleteRegKey HKCU "Software\Classes\AppUserModelId\${APP_NAME}"

DetailPrint "Removing application directory from PATH..."
EnVar::SetHKLM
Expand Down
22 changes: 20 additions & 2 deletions client/netbird.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@
<Component Id="NetbirdFiles" Guid="db3165de-cc6e-4922-8396-9d892950e23e" Bitness="always64">
<File ProcessorArchitecture="$(var.ProcessorArchitecture)" Source=".\dist\netbird_windows_$(var.ArchSuffix)\netbird.exe" KeyPath="yes" />
<File ProcessorArchitecture="$(var.ProcessorArchitecture)" Source=".\dist\netbird_windows_$(var.ArchSuffix)\netbird-ui.exe">
<Shortcut Id="NetbirdDesktopShortcut" Directory="DesktopFolder" Name="NetBird" WorkingDirectory="NetbirdInstallDir" Icon="NetbirdIcon" />
<Shortcut Id="NetbirdStartMenuShortcut" Directory="StartMenuFolder" Name="NetBird" WorkingDirectory="NetbirdInstallDir" Icon="NetbirdIcon" />
<Shortcut Id="NetbirdDesktopShortcut" Directory="DesktopFolder" Name="NetBird" WorkingDirectory="NetbirdInstallDir" Icon="NetbirdIcon">
<ShortcutProperty Key="System.AppUserModel.ID" Value="NetBird" />
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{0E1B4DE7-E148-432B-9814-544F941826EC}" />
</Shortcut>
<Shortcut Id="NetbirdStartMenuShortcut" Directory="StartMenuFolder" Name="NetBird" WorkingDirectory="NetbirdInstallDir" Icon="NetbirdIcon">
<ShortcutProperty Key="System.AppUserModel.ID" Value="NetBird" />
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{0E1B4DE7-E148-432B-9814-544F941826EC}" />
</Shortcut>
</File>
<File ProcessorArchitecture="$(var.ProcessorArchitecture)" Source=".\dist\netbird_windows_$(var.ArchSuffix)\wintun.dll" />
<File Id="NetbirdToastIcon" Name="netbird.png" Source=".\client\ui\assets\netbird.png" />
<?if $(var.ArchSuffix) = "amd64" ?>
<File ProcessorArchitecture="$(var.ProcessorArchitecture)" Source=".\dist\netbird_windows_$(var.ArchSuffix)\opengl32.dll" />
<?endif ?>
Expand All @@ -46,8 +53,19 @@
</Directory>
</StandardDirectory>

<!-- Per-user component: HKCU keypath (auto GUID via "*"), separate from
the per-machine NetbirdFiles component to satisfy ICE57. -->
<StandardDirectory Id="ProgramMenuFolder">
<Component Id="NetbirdAumidRegistry" Guid="*">
<RegistryKey Root="HKCU" Key="Software\Classes\AppUserModelId\NetBird" ForceDeleteOnUninstall="yes">
<RegistryValue Name="InstalledByMSI" Type="integer" Value="1" KeyPath="yes" />
</RegistryKey>
</Component>
</StandardDirectory>

<ComponentGroup Id="NetbirdFilesComponent">
<ComponentRef Id="NetbirdFiles" />
<ComponentRef Id="NetbirdAumidRegistry" />
</ComponentGroup>

<util:CloseApplication Id="CloseNetBird" CloseMessage="no" Target="netbird.exe" RebootPrompt="no" />
Expand Down
9 changes: 6 additions & 3 deletions client/ui/client_ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/netbirdio/netbird/client/proto"
"github.com/netbirdio/netbird/client/ui/desktop"
"github.com/netbirdio/netbird/client/ui/event"
"github.com/netbirdio/netbird/client/ui/notifier"
"github.com/netbirdio/netbird/client/ui/process"
"github.com/netbirdio/netbird/util"

Expand Down Expand Up @@ -260,6 +261,7 @@ type serviceClient struct {

// application with main windows.
app fyne.App
notifier notifier.Notifier
wSettings fyne.Window
showAdvancedSettings bool
sendNotification bool
Expand Down Expand Up @@ -364,6 +366,7 @@ func newServiceClient(args *newServiceClientArgs) *serviceClient {
cancel: cancel,
addr: args.addr,
app: args.app,
notifier: notifier.New(args.app),
logFile: args.logFile,
sendNotification: false,

Expand Down Expand Up @@ -892,7 +895,7 @@ func (s *serviceClient) updateStatus() error {
if err != nil {
log.Errorf("get service status: %v", err)
if s.connected {
s.app.SendNotification(fyne.NewNotification("Error", "Connection to service lost"))
s.notifier.Send("Error", "Connection to service lost")
}
s.setDisconnectedStatus()
return err
Expand Down Expand Up @@ -1109,7 +1112,7 @@ func (s *serviceClient) onTrayReady() {
}
}()

s.eventManager = event.NewManager(s.app, s.addr)
s.eventManager = event.NewManager(s.notifier, s.addr)
s.eventManager.SetNotificationsEnabled(s.mNotifications.Checked())
s.eventManager.AddHandler(func(event *proto.SystemEvent) {
if event.Category == proto.SystemEvent_SYSTEM {
Expand Down Expand Up @@ -1548,7 +1551,7 @@ func (s *serviceClient) onUpdateAvailable(newVersion string, enforced bool) {

if enforced && s.lastNotifiedVersion != newVersion {
s.lastNotifiedVersion = newVersion
s.app.SendNotification(fyne.NewNotification("Update available", "A new version "+newVersion+" is ready to install"))
s.notifier.Send("Update available", "A new version "+newVersion+" is ready to install")
}
}

Expand Down
19 changes: 12 additions & 7 deletions client/ui/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"sync"
"time"

"fyne.io/fyne/v2"
"github.com/cenkalti/backoff/v4"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
Expand All @@ -18,11 +17,17 @@ import (
"github.com/netbirdio/netbird/client/ui/desktop"
)

// Notifier sends desktop notifications. Defined here so the event package
// does not depend on fyne or the platform-specific notifier implementation.
type Notifier interface {
Send(title, body string)
}

type Handler func(*proto.SystemEvent)

type Manager struct {
app fyne.App
addr string
notifier Notifier
addr string

mu sync.Mutex
ctx context.Context
Expand All @@ -31,10 +36,10 @@ type Manager struct {
handlers []Handler
}

func NewManager(app fyne.App, addr string) *Manager {
func NewManager(notifier Notifier, addr string) *Manager {
return &Manager{
app: app,
addr: addr,
notifier: notifier,
addr: addr,
}
}

Expand Down Expand Up @@ -114,7 +119,7 @@ func (e *Manager) handleEvent(event *proto.SystemEvent) {
if id != "" {
body += fmt.Sprintf(" ID: %s", id)
}
e.app.SendNotification(fyne.NewNotification(title, body))
e.notifier.Send(title, body)
}

for _, handler := range handlers {
Expand Down
17 changes: 8 additions & 9 deletions client/ui/event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os"
"os/exec"

"fyne.io/fyne/v2"
"fyne.io/systray"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -87,7 +86,7 @@ func (h *eventHandler) handleConnectClick() {
if errors.Is(err, context.Canceled) || (ok && st.Code() == codes.Canceled) {
log.Debugf("connect operation cancelled by user")
} else {
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to connect"))
h.client.notifier.Send("Error", "Failed to connect")
log.Errorf("connect failed: %v", err)
}
}
Expand All @@ -112,7 +111,7 @@ func (h *eventHandler) handleDisconnectClick() {
if err := h.client.menuDownClick(); err != nil {
st, ok := status.FromError(err)
if !errors.Is(err, context.Canceled) && !(ok && st.Code() == codes.Canceled) {
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to disconnect"))
h.client.notifier.Send("Error", "Failed to disconnect")
log.Errorf("disconnect failed: %v", err)
} else {
log.Debugf("disconnect cancelled or already disconnecting")
Expand All @@ -130,7 +129,7 @@ func (h *eventHandler) handleAllowSSHClick() {
if err := h.updateConfigWithErr(); err != nil {
h.toggleCheckbox(h.client.mAllowSSH) // revert checkbox state on error
log.Errorf("failed to update config: %v", err)
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to update SSH settings"))
h.client.notifier.Send("Error", "Failed to update SSH settings")
}

}
Expand All @@ -140,7 +139,7 @@ func (h *eventHandler) handleAutoConnectClick() {
if err := h.updateConfigWithErr(); err != nil {
h.toggleCheckbox(h.client.mAutoConnect) // revert checkbox state on error
log.Errorf("failed to update config: %v", err)
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to update auto-connect settings"))
h.client.notifier.Send("Error", "Failed to update auto-connect settings")
}
}

Expand All @@ -149,7 +148,7 @@ func (h *eventHandler) handleRosenpassClick() {
if err := h.updateConfigWithErr(); err != nil {
h.toggleCheckbox(h.client.mEnableRosenpass) // revert checkbox state on error
log.Errorf("failed to update config: %v", err)
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to update Rosenpass settings"))
h.client.notifier.Send("Error", "Failed to update Rosenpass settings")
}
}

Expand All @@ -158,7 +157,7 @@ func (h *eventHandler) handleLazyConnectionClick() {
if err := h.updateConfigWithErr(); err != nil {
h.toggleCheckbox(h.client.mLazyConnEnabled) // revert checkbox state on error
log.Errorf("failed to update config: %v", err)
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to update lazy connection settings"))
h.client.notifier.Send("Error", "Failed to update lazy connection settings")
}
}

Expand All @@ -167,7 +166,7 @@ func (h *eventHandler) handleBlockInboundClick() {
if err := h.updateConfigWithErr(); err != nil {
h.toggleCheckbox(h.client.mBlockInbound) // revert checkbox state on error
log.Errorf("failed to update config: %v", err)
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to update block inbound settings"))
h.client.notifier.Send("Error", "Failed to update block inbound settings")
}
}

Expand All @@ -176,7 +175,7 @@ func (h *eventHandler) handleNotificationsClick() {
if err := h.updateConfigWithErr(); err != nil {
h.toggleCheckbox(h.client.mNotifications) // revert checkbox state on error
log.Errorf("failed to update config: %v", err)
h.client.app.SendNotification(fyne.NewNotification("Error", "Failed to update notifications settings"))
h.client.notifier.Send("Error", "Failed to update notifications settings")
} else if h.client.eventManager != nil {
h.client.eventManager.SetNotificationsEnabled(h.client.mNotifications.Checked())
}
Expand Down
27 changes: 27 additions & 0 deletions client/ui/notifier/notifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Package notifier sends desktop notifications. On Windows it uses the WinRT
// COM API directly via go-toast/v2 to avoid the PowerShell window flash that
// fyne's default implementation produces. On other platforms it delegates to
// fyne.
package notifier

import "fyne.io/fyne/v2"

// Notifier sends desktop notifications.
type Notifier interface {
Send(title, body string)
}

// New returns a platform-specific Notifier. The fyne app is used as the
// fallback notifier on platforms where no native implementation is wired up,
// and on Windows when the COM path fails to initialize.
func New(app fyne.App) Notifier {
return newNotifier(app)
}

type fyneNotifier struct {
app fyne.App
}

func (f *fyneNotifier) Send(title, body string) {
f.app.SendNotification(fyne.NewNotification(title, body))
}
9 changes: 9 additions & 0 deletions client/ui/notifier/notifier_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build !windows

package notifier

import "fyne.io/fyne/v2"

func newNotifier(app fyne.App) Notifier {
return &fyneNotifier{app: app}
}
Loading
Loading