Compare commits

...

6 Commits

Author SHA1 Message Date
Pedro Costa
7b02e9c3a8 [management] base manager 2025-03-05 09:52:18 +00:00
hakansa
eee90fbbbf [client] UI Refactor Icon Paths (#3420)
[client] UI Refactor Icon Paths (#3420)
2025-03-05 09:47:29 +00:00
Viktor Liu
85aea0a030 [client] Close userspace firewall properly (#3426) 2025-03-05 09:47:27 +00:00
robertgro
e41acdb9ac [client] Add Netbird GitHub link to the client ui about sub menu (#3372) 2025-03-05 09:46:21 +00:00
Philippe Vaucher
54dc27abec [client Fix env var typo (#3415) 2025-03-05 09:46:21 +00:00
Bethuel Mmbaga
fdd7dc67c0 [management] Handle transaction error on peer deletion (#3387)
Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>
2025-03-05 09:46:21 +00:00
68 changed files with 245 additions and 207 deletions

View File

@@ -71,7 +71,7 @@ jobs:
- name: Install goversioninfo - name: Install goversioninfo
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
- name: Generate windows syso amd64 - name: Generate windows syso amd64
run: goversioninfo -icon client/ui/netbird.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_amd64.syso run: goversioninfo -icon client/ui/assets/netbird.ico -manifest client/manifest.xml -product-name ${{ env.PRODUCT_NAME }} -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/resources_windows_amd64.syso
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4 uses: goreleaser/goreleaser-action@v4
with: with:
@@ -150,7 +150,7 @@ jobs:
- name: Install goversioninfo - name: Install goversioninfo
run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e run: go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@233067e
- name: Generate windows syso amd64 - name: Generate windows syso amd64
run: goversioninfo -64 -icon client/ui/netbird.ico -manifest client/ui/manifest.xml -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_amd64.syso run: goversioninfo -64 -icon client/ui/assets/netbird.ico -manifest client/ui/manifest.xml -product-name ${{ env.PRODUCT_NAME }}-"UI" -copyright "${{ env.COPYRIGHT }}" -ver-major ${{ steps.semver_parser.outputs.major }} -ver-minor ${{ steps.semver_parser.outputs.minor }} -ver-patch ${{ steps.semver_parser.outputs.patch }} -ver-build 0 -file-version ${{ steps.semver_parser.outputs.fullversion }}.0 -product-version ${{ steps.semver_parser.outputs.fullversion }}.0 -o client/ui/resources_windows_amd64.syso
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4 uses: goreleaser/goreleaser-action@v4

View File

@@ -53,9 +53,9 @@ nfpms:
scripts: scripts:
postinstall: "release_files/ui-post-install.sh" postinstall: "release_files/ui-post-install.sh"
contents: contents:
- src: client/ui/netbird.desktop - src: client/ui/build/netbird.desktop
dst: /usr/share/applications/netbird.desktop dst: /usr/share/applications/netbird.desktop
- src: client/ui/netbird.png - src: client/ui/assets/netbird.png
dst: /usr/share/pixmaps/netbird.png dst: /usr/share/pixmaps/netbird.png
dependencies: dependencies:
- netbird - netbird
@@ -72,9 +72,9 @@ nfpms:
scripts: scripts:
postinstall: "release_files/ui-post-install.sh" postinstall: "release_files/ui-post-install.sh"
contents: contents:
- src: client/ui/netbird.desktop - src: client/ui/build/netbird.desktop
dst: /usr/share/applications/netbird.desktop dst: /usr/share/applications/netbird.desktop
- src: client/ui/netbird.png - src: client/ui/assets/netbird.png
dst: /usr/share/pixmaps/netbird.png dst: /usr/share/pixmaps/netbird.png
dependencies: dependencies:
- netbird - netbird

View File

@@ -167,7 +167,7 @@ func (m *Manager) SetLegacyManagement(isLegacy bool) error {
} }
// Reset firewall to the default state // Reset firewall to the default state
func (m *Manager) Reset(stateManager *statemanager.Manager) error { func (m *Manager) Close(stateManager *statemanager.Manager) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()

View File

@@ -62,7 +62,7 @@ func TestIptablesManager(t *testing.T) {
time.Sleep(time.Second) time.Sleep(time.Second)
defer func() { defer func() {
err := manager.Reset(nil) err := manager.Close(nil)
require.NoError(t, err, "clear the manager state") require.NoError(t, err, "clear the manager state")
time.Sleep(time.Second) time.Sleep(time.Second)
@@ -100,14 +100,14 @@ func TestIptablesManager(t *testing.T) {
_, err = manager.AddPeerFiltering(nil, ip, "udp", nil, port, fw.ActionAccept, "") _, err = manager.AddPeerFiltering(nil, ip, "udp", nil, port, fw.ActionAccept, "")
require.NoError(t, err, "failed to add rule") require.NoError(t, err, "failed to add rule")
err = manager.Reset(nil) err = manager.Close(nil)
require.NoError(t, err, "failed to reset") require.NoError(t, err, "failed to reset")
ok, err := ipv4Client.ChainExists("filter", chainNameInputRules) ok, err := ipv4Client.ChainExists("filter", chainNameInputRules)
require.NoError(t, err, "failed check chain exists") require.NoError(t, err, "failed check chain exists")
if ok { if ok {
require.NoErrorf(t, err, "chain '%v' still exists after Reset", chainNameInputRules) require.NoErrorf(t, err, "chain '%v' still exists after Close", chainNameInputRules)
} }
}) })
} }
@@ -136,7 +136,7 @@ func TestIptablesManagerIPSet(t *testing.T) {
time.Sleep(time.Second) time.Sleep(time.Second)
defer func() { defer func() {
err := manager.Reset(nil) err := manager.Close(nil)
require.NoError(t, err, "clear the manager state") require.NoError(t, err, "clear the manager state")
time.Sleep(time.Second) time.Sleep(time.Second)
@@ -166,7 +166,7 @@ func TestIptablesManagerIPSet(t *testing.T) {
}) })
t.Run("reset check", func(t *testing.T) { t.Run("reset check", func(t *testing.T) {
err = manager.Reset(nil) err = manager.Close(nil)
require.NoError(t, err, "failed to reset") require.NoError(t, err, "failed to reset")
}) })
} }
@@ -204,7 +204,7 @@ func TestIptablesCreatePerformance(t *testing.T) {
time.Sleep(time.Second) time.Sleep(time.Second)
defer func() { defer func() {
err := manager.Reset(nil) err := manager.Close(nil)
require.NoError(t, err, "clear the manager state") require.NoError(t, err, "clear the manager state")
time.Sleep(time.Second) time.Sleep(time.Second)

View File

@@ -62,7 +62,7 @@ func (s *ShutdownState) Cleanup() error {
ipt.aclMgr.ipsetStore = s.ACLIPsetStore ipt.aclMgr.ipsetStore = s.ACLIPsetStore
} }
if err := ipt.Reset(nil); err != nil { if err := ipt.Close(nil); err != nil {
return fmt.Errorf("reset iptables manager: %w", err) return fmt.Errorf("reset iptables manager: %w", err)
} }

View File

@@ -102,8 +102,8 @@ type Manager interface {
// SetLegacyManagement sets the legacy management mode // SetLegacyManagement sets the legacy management mode
SetLegacyManagement(legacy bool) error SetLegacyManagement(legacy bool) error
// Reset firewall to the default state // Close closes the firewall manager
Reset(stateManager *statemanager.Manager) error Close(stateManager *statemanager.Manager) error
// Flush the changes to firewall controller // Flush the changes to firewall controller
Flush() error Flush() error

View File

@@ -87,7 +87,7 @@ func (m *Manager) Init(stateManager *statemanager.Manager) error {
// We only need to record minimal interface state for potential recreation. // We only need to record minimal interface state for potential recreation.
// Unlike iptables, which requires tracking individual rules, nftables maintains // Unlike iptables, which requires tracking individual rules, nftables maintains
// a known state (our netbird table plus a few static rules). This allows for easy // a known state (our netbird table plus a few static rules). This allows for easy
// cleanup using Reset() without needing to store specific rules. // cleanup using Close() without needing to store specific rules.
if err := stateManager.UpdateState(&ShutdownState{ if err := stateManager.UpdateState(&ShutdownState{
InterfaceState: &InterfaceState{ InterfaceState: &InterfaceState{
NameStr: m.wgIface.Name(), NameStr: m.wgIface.Name(),
@@ -243,7 +243,7 @@ func (m *Manager) SetLegacyManagement(isLegacy bool) error {
} }
// Reset firewall to the default state // Reset firewall to the default state
func (m *Manager) Reset(stateManager *statemanager.Manager) error { func (m *Manager) Close(stateManager *statemanager.Manager) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()

View File

@@ -65,7 +65,7 @@ func TestNftablesManager(t *testing.T) {
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
defer func() { defer func() {
err = manager.Reset(nil) err = manager.Close(nil)
require.NoError(t, err, "failed to reset") require.NoError(t, err, "failed to reset")
time.Sleep(time.Second) time.Sleep(time.Second)
}() }()
@@ -162,7 +162,7 @@ func TestNftablesManager(t *testing.T) {
// established rule remains // established rule remains
require.Len(t, rules, 1, "expected 1 rules after deletion") require.Len(t, rules, 1, "expected 1 rules after deletion")
err = manager.Reset(nil) err = manager.Close(nil)
require.NoError(t, err, "failed to reset") require.NoError(t, err, "failed to reset")
} }
@@ -191,7 +191,7 @@ func TestNFtablesCreatePerformance(t *testing.T) {
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
defer func() { defer func() {
if err := manager.Reset(nil); err != nil { if err := manager.Close(nil); err != nil {
t.Errorf("clear the manager state: %v", err) t.Errorf("clear the manager state: %v", err)
} }
time.Sleep(time.Second) time.Sleep(time.Second)
@@ -274,7 +274,7 @@ func TestNftablesManagerCompatibilityWithIptables(t *testing.T) {
require.NoError(t, manager.Init(nil)) require.NoError(t, manager.Init(nil))
t.Cleanup(func() { t.Cleanup(func() {
err := manager.Reset(nil) err := manager.Close(nil)
require.NoError(t, err, "failed to reset manager state") require.NoError(t, err, "failed to reset manager state")
// Verify iptables output after reset // Verify iptables output after reset

View File

@@ -38,7 +38,7 @@ func TestNftablesManager_AddNatRule(t *testing.T) {
// need fw manager to init both acl mgr and router for all chains to be present // need fw manager to init both acl mgr and router for all chains to be present
manager, err := Create(ifaceMock) manager, err := Create(ifaceMock)
t.Cleanup(func() { t.Cleanup(func() {
require.NoError(t, manager.Reset(nil)) require.NoError(t, manager.Close(nil))
}) })
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, manager.Init(nil)) require.NoError(t, manager.Init(nil))
@@ -127,7 +127,7 @@ func TestNftablesManager_RemoveNatRule(t *testing.T) {
t.Run(testCase.Name, func(t *testing.T) { t.Run(testCase.Name, func(t *testing.T) {
manager, err := Create(ifaceMock) manager, err := Create(ifaceMock)
t.Cleanup(func() { t.Cleanup(func() {
require.NoError(t, manager.Reset(nil)) require.NoError(t, manager.Close(nil))
}) })
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, manager.Init(nil)) require.NoError(t, manager.Init(nil))

View File

@@ -39,7 +39,7 @@ func (s *ShutdownState) Cleanup() error {
return fmt.Errorf("create nftables manager: %w", err) return fmt.Errorf("create nftables manager: %w", err)
} }
if err := nft.Reset(nil); err != nil { if err := nft.Close(nil); err != nil {
return fmt.Errorf("reset nftables manager: %w", err) return fmt.Errorf("reset nftables manager: %w", err)
} }

View File

@@ -13,7 +13,7 @@ import (
) )
// Reset firewall to the default state // Reset firewall to the default state
func (m *Manager) Reset(stateManager *statemanager.Manager) error { func (m *Manager) Close(stateManager *statemanager.Manager) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
@@ -48,7 +48,7 @@ func (m *Manager) Reset(stateManager *statemanager.Manager) error {
} }
if m.nativeFirewall != nil { if m.nativeFirewall != nil {
return m.nativeFirewall.Reset(stateManager) return m.nativeFirewall.Close(stateManager)
} }
return nil return nil
} }

View File

@@ -21,8 +21,8 @@ const (
firewallRuleName = "Netbird" firewallRuleName = "Netbird"
) )
// Reset firewall to the default state // Close closes the firewall manager
func (m *Manager) Reset(*statemanager.Manager) error { func (m *Manager) Close(*statemanager.Manager) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()

View File

@@ -171,7 +171,7 @@ func BenchmarkCoreFiltering(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
defer b.Cleanup(func() { defer b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.wgNetwork = &net.IPNet{ manager.wgNetwork = &net.IPNet{
@@ -216,7 +216,7 @@ func BenchmarkStateScaling(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
b.Cleanup(func() { b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.wgNetwork = &net.IPNet{ manager.wgNetwork = &net.IPNet{
@@ -264,7 +264,7 @@ func BenchmarkEstablishmentOverhead(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
b.Cleanup(func() { b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.wgNetwork = &net.IPNet{ manager.wgNetwork = &net.IPNet{
@@ -463,7 +463,7 @@ func BenchmarkRoutedNetworkReturn(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
b.Cleanup(func() { b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
// Setup scenario // Setup scenario
@@ -590,7 +590,7 @@ func BenchmarkLongLivedConnections(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
defer b.Cleanup(func() { defer b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.SetNetwork(&net.IPNet{ manager.SetNetwork(&net.IPNet{
@@ -678,7 +678,7 @@ func BenchmarkShortLivedConnections(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
defer b.Cleanup(func() { defer b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.SetNetwork(&net.IPNet{ manager.SetNetwork(&net.IPNet{
@@ -794,7 +794,7 @@ func BenchmarkParallelLongLivedConnections(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
defer b.Cleanup(func() { defer b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.SetNetwork(&net.IPNet{ manager.SetNetwork(&net.IPNet{
@@ -879,7 +879,7 @@ func BenchmarkParallelShortLivedConnections(b *testing.B) {
SetFilterFunc: func(device.PacketFilter) error { return nil }, SetFilterFunc: func(device.PacketFilter) error { return nil },
}, false, flowLogger) }, false, flowLogger)
defer b.Cleanup(func() { defer b.Cleanup(func() {
require.NoError(b, manager.Reset(nil)) require.NoError(b, manager.Close(nil))
}) })
manager.SetNetwork(&net.IPNet{ manager.SetNetwork(&net.IPNet{

View File

@@ -39,7 +39,7 @@ func TestPeerACLFiltering(t *testing.T) {
require.NotNil(t, manager) require.NotNil(t, manager)
t.Cleanup(func() { t.Cleanup(func() {
require.NoError(t, manager.Reset(nil)) require.NoError(t, manager.Close(nil))
}) })
manager.wgNetwork = wgNet manager.wgNetwork = wgNet
@@ -310,7 +310,7 @@ func setupRoutedManager(tb testing.TB, network string) *Manager {
require.False(tb, manager.nativeRouter) require.False(tb, manager.nativeRouter)
tb.Cleanup(func() { tb.Cleanup(func() {
require.NoError(tb, manager.Reset(nil)) require.NoError(tb, manager.Close(nil))
}) })
return manager return manager

View File

@@ -255,7 +255,7 @@ func TestManagerReset(t *testing.T) {
return return
} }
err = m.Reset(nil) err = m.Close(nil)
if err != nil { if err != nil {
t.Errorf("failed to reset Manager: %v", err) t.Errorf("failed to reset Manager: %v", err)
return return
@@ -333,7 +333,7 @@ func TestNotMatchByIP(t *testing.T) {
return return
} }
if err = m.Reset(nil); err != nil { if err = m.Close(nil); err != nil {
t.Errorf("failed to reset Manager: %v", err) t.Errorf("failed to reset Manager: %v", err)
return return
} }
@@ -352,7 +352,7 @@ func TestRemovePacketHook(t *testing.T) {
t.Fatalf("Failed to create Manager: %s", err) t.Fatalf("Failed to create Manager: %s", err)
} }
defer func() { defer func() {
require.NoError(t, manager.Reset(nil)) require.NoError(t, manager.Close(nil))
}() }()
// Add a UDP packet hook // Add a UDP packet hook
@@ -403,7 +403,7 @@ func TestProcessOutgoingHooks(t *testing.T) {
manager.udpTracker.Close() manager.udpTracker.Close()
manager.udpTracker = conntrack.NewUDPTracker(100*time.Millisecond, logger, flowLogger) manager.udpTracker = conntrack.NewUDPTracker(100*time.Millisecond, logger, flowLogger)
defer func() { defer func() {
require.NoError(t, manager.Reset(nil)) require.NoError(t, manager.Close(nil))
}() }()
manager.decoders = sync.Pool{ manager.decoders = sync.Pool{
@@ -484,7 +484,7 @@ func TestUSPFilterCreatePerformance(t *testing.T) {
time.Sleep(time.Second) time.Sleep(time.Second)
defer func() { defer func() {
if err := manager.Reset(nil); err != nil { if err := manager.Close(nil); err != nil {
t.Errorf("clear the manager state: %v", err) t.Errorf("clear the manager state: %v", err)
} }
time.Sleep(time.Second) time.Sleep(time.Second)
@@ -530,7 +530,7 @@ func TestStatefulFirewall_UDPTracking(t *testing.T) {
}, },
} }
defer func() { defer func() {
require.NoError(t, manager.Reset(nil)) require.NoError(t, manager.Close(nil))
}() }()
// Set up packet parameters // Set up packet parameters

View File

@@ -55,7 +55,7 @@ func (t *NetStackTun) Create() (tun.Device, *netstack.Net, error) {
skipProxy, err := strconv.ParseBool(os.Getenv(EnvSkipProxy)) skipProxy, err := strconv.ParseBool(os.Getenv(EnvSkipProxy))
if err != nil { if err != nil {
log.Errorf("failed to parse NB_ETSTACK_SKIP_PROXY: %s", err) log.Errorf("failed to parse %s: %s", EnvSkipProxy, err)
} }
if skipProxy { if skipProxy {
return nsTunDev, tunNet, nil return nsTunDev, tunNet, nil

View File

@@ -6,8 +6,8 @@
!define DESCRIPTION "A WireGuard®-based mesh network that connects your devices into a single private network" !define DESCRIPTION "A WireGuard®-based mesh network that connects your devices into a single private network"
!define INSTALLER_NAME "netbird-installer.exe" !define INSTALLER_NAME "netbird-installer.exe"
!define MAIN_APP_EXE "Netbird" !define MAIN_APP_EXE "Netbird"
!define ICON "ui\\netbird.ico" !define ICON "ui\\assets\\netbird.ico"
!define BANNER "ui\\banner.bmp" !define BANNER "ui\\build\\banner.bmp"
!define LICENSE_DATA "..\\LICENSE" !define LICENSE_DATA "..\\LICENSE"
!define INSTALL_DIR "$PROGRAMFILES64\${APP_NAME}" !define INSTALL_DIR "$PROGRAMFILES64\${APP_NAME}"

View File

@@ -62,7 +62,7 @@ func TestDefaultManager(t *testing.T) {
return return
} }
defer func(fw manager.Manager) { defer func(fw manager.Manager) {
_ = fw.Reset(nil) _ = fw.Close(nil)
}(fw) }(fw)
acl := NewDefaultManager(fw) acl := NewDefaultManager(fw)
@@ -356,7 +356,7 @@ func TestDefaultManagerEnableSSHRules(t *testing.T) {
return return
} }
defer func(fw manager.Manager) { defer func(fw manager.Manager) {
_ = fw.Reset(nil) _ = fw.Close(nil)
}(fw) }(fw)
acl := NewDefaultManager(fw) acl := NewDefaultManager(fw)

View File

@@ -1018,7 +1018,7 @@ func TestHandlerChain_DomainPriorities(t *testing.T) {
mh.AssertExpectations(t) mh.AssertExpectations(t)
} }
// Reset mocks // Close mocks
if mh, ok := tc.expectedHandler.(*MockHandler); ok { if mh, ok := tc.expectedHandler.(*MockHandler); ok {
mh.ExpectedCalls = nil mh.ExpectedCalls = nil
mh.Calls = nil mh.Calls = nil

View File

@@ -1428,7 +1428,7 @@ func (e *Engine) close() {
} }
if e.firewall != nil { if e.firewall != nil {
err := e.firewall.Reset(e.stateManager) err := e.firewall.Close(e.stateManager)
if err != nil { if err != nil {
log.Warnf("failed to reset firewall: %s", err) log.Warnf("failed to reset firewall: %s", err)
} }

View File

@@ -71,7 +71,7 @@
</InstallExecuteSequence> </InstallExecuteSequence>
<!-- Icons --> <!-- Icons -->
<Icon Id="NetbirdIcon" SourceFile=".\client\ui\netbird.ico" /> <Icon Id="NetbirdIcon" SourceFile=".\client\ui\assets\netbird.ico" />
<Property Id="ARPPRODUCTICON" Value="NetbirdIcon" /> <Property Id="ARPPRODUCTICON" Value="NetbirdIcon" />
</Package> </Package>

View File

@@ -5,5 +5,5 @@
#define STRINGIZE(x) #x #define STRINGIZE(x) #x
#define EXPAND(x) STRINGIZE(x) #define EXPAND(x) STRINGIZE(x)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml
7 ICON ui/netbird.ico 7 ICON ui/assets/netbird.ico
wintun.dll RCDATA wintun.dll wintun.dll RCDATA wintun.dll

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -35,7 +35,9 @@ import (
"github.com/netbirdio/netbird/client/proto" "github.com/netbirdio/netbird/client/proto"
"github.com/netbirdio/netbird/client/ui/desktop" "github.com/netbirdio/netbird/client/ui/desktop"
"github.com/netbirdio/netbird/client/ui/event" "github.com/netbirdio/netbird/client/ui/event"
"github.com/netbirdio/netbird/client/ui/process"
"github.com/netbirdio/netbird/util" "github.com/netbirdio/netbird/util"
"github.com/netbirdio/netbird/version" "github.com/netbirdio/netbird/version"
) )
@@ -44,94 +46,125 @@ const (
failFastTimeout = time.Second failFastTimeout = time.Second
) )
const (
censoredPreSharedKey = "**********"
)
func main() { func main() {
var daemonAddr string daemonAddr, showSettings, showNetworks, errorMsg, saveLogsInFile := parseFlags()
defaultDaemonAddr := "unix:///var/run/netbird.sock"
if runtime.GOOS == "windows" {
defaultDaemonAddr = "tcp://127.0.0.1:41731"
}
flag.StringVar(
&daemonAddr, "daemon-addr",
defaultDaemonAddr,
"Daemon service address to serve CLI requests [unix|tcp]://[path|host:port]")
var showSettings bool
flag.BoolVar(&showSettings, "settings", false, "run settings windows")
var showRoutes bool
flag.BoolVar(&showRoutes, "networks", false, "run networks windows")
var errorMSG string
flag.StringVar(&errorMSG, "error-msg", "", "displays a error message window")
tmpDir := "/tmp"
if runtime.GOOS == "windows" {
tmpDir = os.TempDir()
}
var saveLogsInFile bool
flag.BoolVar(&saveLogsInFile, "use-log-file", false, fmt.Sprintf("save logs in a file: %s/netbird-ui-PID.log", tmpDir))
flag.Parse()
// Initialize file logging if needed.
if saveLogsInFile { if saveLogsInFile {
logFile := path.Join(tmpDir, fmt.Sprintf("netbird-ui-%d.log", os.Getpid())) if err := initLogFile(); err != nil {
err := util.InitLog("trace", logFile)
if err != nil {
log.Errorf("error while initializing log: %v", err) log.Errorf("error while initializing log: %v", err)
return return
} }
} }
// Create the Fyne application.
a := app.NewWithID("NetBird") a := app.NewWithID("NetBird")
a.SetIcon(fyne.NewStaticResource("netbird", iconDisconnected)) a.SetIcon(fyne.NewStaticResource("netbird", iconDisconnected))
if errorMSG != "" { // Show error message window if needed.
showErrorMSG(errorMSG) if errorMsg != "" {
showErrorMessage(errorMsg)
return return
} }
client := newServiceClient(daemonAddr, a, showSettings, showRoutes) // Create the service client (this also builds the settings or networks UI if requested).
client := newServiceClient(daemonAddr, a, showSettings, showNetworks)
// Watch for theme/settings changes to update the icon.
go watchSettingsChanges(a, client)
// Run in window mode if any UI flag was set.
if showSettings || showNetworks {
a.Run()
return
}
// Check for another running process.
running, err := process.IsAnotherProcessRunning()
if err != nil {
log.Errorf("error while checking process: %v", err)
return
}
if running {
log.Warn("another process is running")
return
}
client.setDefaultFonts()
systray.Run(client.onTrayReady, client.onTrayExit)
}
// parseFlags reads and returns all needed command-line flags.
func parseFlags() (daemonAddr string, showSettings, showNetworks bool, errorMsg string, saveLogsInFile bool) {
defaultDaemonAddr := "unix:///var/run/netbird.sock"
if runtime.GOOS == "windows" {
defaultDaemonAddr = "tcp://127.0.0.1:41731"
}
flag.StringVar(&daemonAddr, "daemon-addr", defaultDaemonAddr, "Daemon service address to serve CLI requests [unix|tcp]://[path|host:port]")
flag.BoolVar(&showSettings, "settings", false, "run settings window")
flag.BoolVar(&showNetworks, "networks", false, "run networks window")
flag.StringVar(&errorMsg, "error-msg", "", "displays an error message window")
tmpDir := "/tmp"
if runtime.GOOS == "windows" {
tmpDir = os.TempDir()
}
flag.BoolVar(&saveLogsInFile, "use-log-file", false, fmt.Sprintf("save logs in a file: %s/netbird-ui-PID.log", tmpDir))
flag.Parse()
return
}
// initLogFile initializes logging into a file.
func initLogFile() error {
tmpDir := "/tmp"
if runtime.GOOS == "windows" {
tmpDir = os.TempDir()
}
logFile := path.Join(tmpDir, fmt.Sprintf("netbird-ui-%d.log", os.Getpid()))
return util.InitLog("trace", logFile)
}
// watchSettingsChanges listens for Fyne theme/settings changes and updates the client icon.
func watchSettingsChanges(a fyne.App, client *serviceClient) {
settingsChangeChan := make(chan fyne.Settings) settingsChangeChan := make(chan fyne.Settings)
a.Settings().AddChangeListener(settingsChangeChan) a.Settings().AddChangeListener(settingsChangeChan)
go func() { for range settingsChangeChan {
for range settingsChangeChan { client.updateIcon()
client.updateIcon()
}
}()
if showSettings || showRoutes {
a.Run()
} else {
running, err := isAnotherProcessRunning()
if err != nil {
log.Errorf("error while checking process: %v", err)
}
if running {
log.Warn("another process is running")
return
}
client.setDefaultFonts()
systray.Run(client.onTrayReady, client.onTrayExit)
} }
} }
//go:embed netbird-systemtray-connected-macos.png // showErrorMessage displays an error message in a simple window.
func showErrorMessage(msg string) {
a := app.New()
w := a.NewWindow("NetBird Error")
label := widget.NewLabel(msg)
label.Wrapping = fyne.TextWrapWord
w.SetContent(label)
w.Resize(fyne.NewSize(400, 100))
w.Show()
a.Run()
}
//go:embed assets/netbird-systemtray-connected-macos.png
var iconConnectedMacOS []byte var iconConnectedMacOS []byte
//go:embed netbird-systemtray-disconnected-macos.png //go:embed assets/netbird-systemtray-disconnected-macos.png
var iconDisconnectedMacOS []byte var iconDisconnectedMacOS []byte
//go:embed netbird-systemtray-update-disconnected-macos.png //go:embed assets/netbird-systemtray-update-disconnected-macos.png
var iconUpdateDisconnectedMacOS []byte var iconUpdateDisconnectedMacOS []byte
//go:embed netbird-systemtray-update-connected-macos.png //go:embed assets/netbird-systemtray-update-connected-macos.png
var iconUpdateConnectedMacOS []byte var iconUpdateConnectedMacOS []byte
//go:embed netbird-systemtray-connecting-macos.png //go:embed assets/netbird-systemtray-connecting-macos.png
var iconConnectingMacOS []byte var iconConnectingMacOS []byte
//go:embed netbird-systemtray-error-macos.png //go:embed assets/netbird-systemtray-error-macos.png
var iconErrorMacOS []byte var iconErrorMacOS []byte
type serviceClient struct { type serviceClient struct {
@@ -154,6 +187,7 @@ type serviceClient struct {
mAdminPanel *systray.MenuItem mAdminPanel *systray.MenuItem
mSettings *systray.MenuItem mSettings *systray.MenuItem
mAbout *systray.MenuItem mAbout *systray.MenuItem
mGitHub *systray.MenuItem
mVersionUI *systray.MenuItem mVersionUI *systray.MenuItem
mVersionDaemon *systray.MenuItem mVersionDaemon *systray.MenuItem
mUpdate *systray.MenuItem mUpdate *systray.MenuItem
@@ -300,18 +334,6 @@ func (s *serviceClient) showSettingsUI() {
s.wSettings.Show() s.wSettings.Show()
} }
// showErrorMSG opens a fyne app window to display the supplied message
func showErrorMSG(msg string) {
app := app.New()
w := app.NewWindow("NetBird Error")
content := widget.NewLabel(msg)
content.Wrapping = fyne.TextWrapWord
w.SetContent(content)
w.Resize(fyne.NewSize(400, 100))
w.Show()
app.Run()
}
// getSettingsForm to embed it into settings window. // getSettingsForm to embed it into settings window.
func (s *serviceClient) getSettingsForm() *widget.Form { func (s *serviceClient) getSettingsForm() *widget.Form {
return &widget.Form{ return &widget.Form{
@@ -327,7 +349,7 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
}, },
SubmitText: "Save", SubmitText: "Save",
OnSubmit: func() { OnSubmit: func() {
if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != "**********" { if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != censoredPreSharedKey {
// validate preSharedKey if it added // validate preSharedKey if it added
if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil { if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil {
dialog.ShowError(fmt.Errorf("Invalid Pre-shared Key Value"), s.wSettings) dialog.ShowError(fmt.Errorf("Invalid Pre-shared Key Value"), s.wSettings)
@@ -365,7 +387,7 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
WireguardPort: &port, WireguardPort: &port,
} }
if s.iPreSharedKey.Text != "**********" { if s.iPreSharedKey.Text != censoredPreSharedKey {
loginRequest.OptionalPreSharedKey = &s.iPreSharedKey.Text loginRequest.OptionalPreSharedKey = &s.iPreSharedKey.Text
} }
@@ -587,26 +609,29 @@ func (s *serviceClient) onTrayReady() {
s.mAdminPanel = systray.AddMenuItem("Admin Panel", "Netbird Admin Panel") s.mAdminPanel = systray.AddMenuItem("Admin Panel", "Netbird Admin Panel")
systray.AddSeparator() systray.AddSeparator()
s.mSettings = systray.AddMenuItem("Settings", "Settings of the application") s.mSettings = systray.AddMenuItem("Settings", settingsMenuDescr)
s.mAllowSSH = s.mSettings.AddSubMenuItemCheckbox("Allow SSH", "Allow SSH connections", false) s.mAllowSSH = s.mSettings.AddSubMenuItemCheckbox("Allow SSH", allowSSHMenuDescr, false)
s.mAutoConnect = s.mSettings.AddSubMenuItemCheckbox("Connect on Startup", "Connect automatically when the service starts", false) s.mAutoConnect = s.mSettings.AddSubMenuItemCheckbox("Connect on Startup", autoConnectMenuDescr, false)
s.mEnableRosenpass = s.mSettings.AddSubMenuItemCheckbox("Enable Quantum-Resistance", "Enable post-quantum security via Rosenpass", false) s.mEnableRosenpass = s.mSettings.AddSubMenuItemCheckbox("Enable Quantum-Resistance", quantumResistanceMenuDescr, false)
s.mNotifications = s.mSettings.AddSubMenuItemCheckbox("Notifications", "Enable notifications", false) s.mNotifications = s.mSettings.AddSubMenuItemCheckbox("Notifications", notificationsMenuDescr, false)
s.mAdvancedSettings = s.mSettings.AddSubMenuItem("Advanced Settings", "Advanced settings of the application") s.mAdvancedSettings = s.mSettings.AddSubMenuItem("Advanced Settings", advancedSettingsMenuDescr)
s.mCreateDebugBundle = s.mSettings.AddSubMenuItem("Create Debug Bundle", "Create and open debug information bundle") s.mCreateDebugBundle = s.mSettings.AddSubMenuItem("Create Debug Bundle", debugBundleMenuDescr)
s.loadSettings() s.loadSettings()
s.exitNodeMu.Lock() s.exitNodeMu.Lock()
s.mExitNode = systray.AddMenuItem("Exit Node", "Select exit node for routing traffic") s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
s.mExitNode.Disable() s.mExitNode.Disable()
s.exitNodeMu.Unlock() s.exitNodeMu.Unlock()
s.mNetworks = systray.AddMenuItem("Networks", "Open the networks management window") s.mNetworks = systray.AddMenuItem("Networks", networksMenuDescr)
s.mNetworks.Disable() s.mNetworks.Disable()
systray.AddSeparator() systray.AddSeparator()
s.mAbout = systray.AddMenuItem("About", "About") s.mAbout = systray.AddMenuItem("About", "About")
s.mAbout.SetIcon(s.icAbout) s.mAbout.SetIcon(s.icAbout)
s.mGitHub = s.mAbout.AddSubMenuItem("GitHub", "GitHub")
versionString := normalizedVersion(version.NetbirdVersion()) versionString := normalizedVersion(version.NetbirdVersion())
s.mVersionUI = s.mAbout.AddSubMenuItem(fmt.Sprintf("GUI: %s", versionString), fmt.Sprintf("GUI Version: %s", versionString)) s.mVersionUI = s.mAbout.AddSubMenuItem(fmt.Sprintf("GUI: %s", versionString), fmt.Sprintf("GUI Version: %s", versionString))
s.mVersionUI.Disable() s.mVersionUI.Disable()
@@ -615,11 +640,11 @@ func (s *serviceClient) onTrayReady() {
s.mVersionDaemon.Disable() s.mVersionDaemon.Disable()
s.mVersionDaemon.Hide() s.mVersionDaemon.Hide()
s.mUpdate = s.mAbout.AddSubMenuItem("Download latest version", "Download latest version") s.mUpdate = s.mAbout.AddSubMenuItem("Download latest version", latestVersionMenuDescr)
s.mUpdate.Hide() s.mUpdate.Hide()
systray.AddSeparator() systray.AddSeparator()
s.mQuit = systray.AddMenuItem("Quit", "Quit the client app") s.mQuit = systray.AddMenuItem("Quit", quitMenuDescr)
// update exit node menu in case service is already connected // update exit node menu in case service is already connected
go s.updateExitNodes() go s.updateExitNodes()
@@ -717,6 +742,11 @@ func (s *serviceClient) onTrayReady() {
case <-s.mQuit.ClickedCh: case <-s.mQuit.ClickedCh:
systray.Quit() systray.Quit()
return return
case <-s.mGitHub.ClickedCh:
err := openURL("https://github.com/netbirdio/netbird")
if err != nil {
log.Errorf("%s", err)
}
case <-s.mUpdate.ClickedCh: case <-s.mUpdate.ClickedCh:
err := openURL(version.DownloadUrl()) err := openURL(version.DownloadUrl())
if err != nil { if err != nil {

15
client/ui/const.go Normal file
View File

@@ -0,0 +1,15 @@
package main
const (
settingsMenuDescr = "Settings of the application"
allowSSHMenuDescr = "Allow SSH connections"
autoConnectMenuDescr = "Connect automatically when the service starts"
quantumResistanceMenuDescr = "Enable post-quantum security via Rosenpass"
notificationsMenuDescr = "Enable notifications"
advancedSettingsMenuDescr = "Advanced settings of the application"
debugBundleMenuDescr = "Create and open debug information bundle"
exitNodeMenuDescr = "Select exit node for routing traffic"
networksMenuDescr = "Open the networks management window"
latestVersionMenuDescr = "Download latest version"
quitMenuDescr = "Quit the client app"
)

View File

@@ -6,38 +6,38 @@ import (
_ "embed" _ "embed"
) )
//go:embed netbird.png //go:embed assets/netbird.png
var iconAbout []byte var iconAbout []byte
//go:embed netbird-systemtray-connected.png //go:embed assets/netbird-systemtray-connected.png
var iconConnected []byte var iconConnected []byte
//go:embed netbird-systemtray-connected-dark.png //go:embed assets/netbird-systemtray-connected-dark.png
var iconConnectedDark []byte var iconConnectedDark []byte
//go:embed netbird-systemtray-disconnected.png //go:embed assets/netbird-systemtray-disconnected.png
var iconDisconnected []byte var iconDisconnected []byte
//go:embed netbird-systemtray-update-disconnected.png //go:embed assets/netbird-systemtray-update-disconnected.png
var iconUpdateDisconnected []byte var iconUpdateDisconnected []byte
//go:embed netbird-systemtray-update-disconnected-dark.png //go:embed assets/netbird-systemtray-update-disconnected-dark.png
var iconUpdateDisconnectedDark []byte var iconUpdateDisconnectedDark []byte
//go:embed netbird-systemtray-update-connected.png //go:embed assets/netbird-systemtray-update-connected.png
var iconUpdateConnected []byte var iconUpdateConnected []byte
//go:embed netbird-systemtray-update-connected-dark.png //go:embed assets/netbird-systemtray-update-connected-dark.png
var iconUpdateConnectedDark []byte var iconUpdateConnectedDark []byte
//go:embed netbird-systemtray-connecting.png //go:embed assets/netbird-systemtray-connecting.png
var iconConnecting []byte var iconConnecting []byte
//go:embed netbird-systemtray-connecting-dark.png //go:embed assets/netbird-systemtray-connecting-dark.png
var iconConnectingDark []byte var iconConnectingDark []byte
//go:embed netbird-systemtray-error.png //go:embed assets/netbird-systemtray-error.png
var iconError []byte var iconError []byte
//go:embed netbird-systemtray-error-dark.png //go:embed assets/netbird-systemtray-error-dark.png
var iconErrorDark []byte var iconErrorDark []byte

View File

@@ -1,41 +1,41 @@
package main package main
import ( import (
_ "embed" _ "embed"
) )
//go:embed netbird.ico //go:embed assets/netbird.ico
var iconAbout []byte var iconAbout []byte
//go:embed netbird-systemtray-connected.ico //go:embed assets/netbird-systemtray-connected.ico
var iconConnected []byte var iconConnected []byte
//go:embed netbird-systemtray-connected-dark.ico //go:embed assets/netbird-systemtray-connected-dark.ico
var iconConnectedDark []byte var iconConnectedDark []byte
//go:embed netbird-systemtray-disconnected.ico //go:embed assets/netbird-systemtray-disconnected.ico
var iconDisconnected []byte var iconDisconnected []byte
//go:embed netbird-systemtray-update-disconnected.ico //go:embed assets/netbird-systemtray-update-disconnected.ico
var iconUpdateDisconnected []byte var iconUpdateDisconnected []byte
//go:embed netbird-systemtray-update-disconnected-dark.ico //go:embed assets/netbird-systemtray-update-disconnected-dark.ico
var iconUpdateDisconnectedDark []byte var iconUpdateDisconnectedDark []byte
//go:embed netbird-systemtray-update-connected.ico //go:embed assets/netbird-systemtray-update-connected.ico
var iconUpdateConnected []byte var iconUpdateConnected []byte
//go:embed netbird-systemtray-update-connected-dark.ico //go:embed assets/netbird-systemtray-update-connected-dark.ico
var iconUpdateConnectedDark []byte var iconUpdateConnectedDark []byte
//go:embed netbird-systemtray-connecting.ico //go:embed assets/netbird-systemtray-connecting.ico
var iconConnecting []byte var iconConnecting []byte
//go:embed netbird-systemtray-connecting-dark.ico //go:embed assets/netbird-systemtray-connecting-dark.ico
var iconConnectingDark []byte var iconConnectingDark []byte
//go:embed netbird-systemtray-error.ico //go:embed assets/netbird-systemtray-error.ico
var iconError []byte var iconError []byte
//go:embed netbird-systemtray-error-dark.ico //go:embed assets/netbird-systemtray-error-dark.ico
var iconErrorDark []byte var iconErrorDark []byte

View File

@@ -363,7 +363,7 @@ func (s *serviceClient) recreateExitNodeMenu(exitNodes []*proto.Network) {
if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" { if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" {
s.mExitNode.Remove() s.mExitNode.Remove()
s.mExitNode = systray.AddMenuItem("Exit Node", "Select exit node for routing traffic") s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
} }
for _, node := range exitNodes { for _, node := range exitNodes {

View File

@@ -1,4 +1,4 @@
package main package process
import ( import (
"os" "os"
@@ -8,7 +8,7 @@ import (
"github.com/shirou/gopsutil/v3/process" "github.com/shirou/gopsutil/v3/process"
) )
func isAnotherProcessRunning() (bool, error) { func IsAnotherProcessRunning() (bool, error) {
processes, err := process.Processes() processes, err := process.Processes()
if err != nil { if err != nil {
return false, err return false, err

View File

@@ -1,6 +1,6 @@
//go:build !windows //go:build !windows
package main package process
import ( import (
"os" "os"

View File

@@ -1,4 +1,4 @@
package main package process
import ( import (
"os/user" "os/user"

5
go.mod
View File

@@ -60,7 +60,8 @@ require (
github.com/miekg/dns v1.1.59 github.com/miekg/dns v1.1.59
github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/nadoo/ipset v0.5.0 github.com/nadoo/ipset v0.5.0
github.com/netbirdio/management-integrations/integrations v0.0.0-20250226165736-0ac3dc443266 github.com/netbirdio/management-integrations/core v0.0.0-00010101000000-000000000000
github.com/netbirdio/management-integrations/integrations v0.0.0-20250220173202-e599d83524fc
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20241010133937-e0df50df217d github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20241010133937-e0df50df217d
github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/okta/okta-sdk-golang/v2 v2.18.0
github.com/oschwald/maxminddb-golang v1.12.0 github.com/oschwald/maxminddb-golang v1.12.0
@@ -254,3 +255,5 @@ replace github.com/cloudflare/circl => github.com/cunicu/circl v0.0.0-2023080111
replace github.com/pion/ice/v3 => github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e replace github.com/pion/ice/v3 => github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e
replace github.com/libp2p/go-netroute => github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944 replace github.com/libp2p/go-netroute => github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944
replace github.com/netbirdio/management-integrations/core => ../../management-integrations/core

View File

@@ -34,7 +34,6 @@ var tokenPathRegexp = regexp.MustCompile(`^.*/api/users/.*/tokens.*$`)
// Handler method of the middleware which forbids all modify requests for non admin users // Handler method of the middleware which forbids all modify requests for non admin users
func (a *AccessControl) Handler(h http.Handler) http.Handler { func (a *AccessControl) Handler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if bypass.ShouldBypass(r.URL.Path, h, w, r) { if bypass.ShouldBypass(r.URL.Path, h, w, r) {
return return
} }
@@ -60,18 +59,16 @@ func (a *AccessControl) Handler(h http.Handler) http.Handler {
if !user.HasAdminPower() { if !user.HasAdminPower() {
switch r.Method { switch r.Method {
case http.MethodDelete, http.MethodPost, http.MethodPatch, http.MethodPut: case http.MethodDelete, http.MethodPost, http.MethodPatch, http.MethodPut:
if !tokenPathRegexp.MatchString(r.URL.Path) {
if tokenPathRegexp.MatchString(r.URL.Path) { util.WriteError(r.Context(), status.Errorf(status.PermissionDenied, "only users with admin power can perform this operation"), w)
log.WithContext(r.Context()).Debugf("valid Path")
h.ServeHTTP(w, r)
return return
} }
util.WriteError(r.Context(), status.Errorf(status.PermissionDenied, "only users with admin power can perform this operation"), w) log.WithContext(r.Context()).Debugf("valid Path")
return
} }
} }
// @todo get account settings and set it and user to context
h.ServeHTTP(w, r) h.ServeHTTP(w, r)
}) })
} }

View File

@@ -6,13 +6,13 @@ import (
"github.com/rs/xid" "github.com/rs/xid"
"github.com/netbirdio/management-integrations/core"
"github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/account"
"github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/networks/resources" "github.com/netbirdio/netbird/management/server/networks/resources"
"github.com/netbirdio/netbird/management/server/networks/routers" "github.com/netbirdio/netbird/management/server/networks/routers"
"github.com/netbirdio/netbird/management/server/networks/types" "github.com/netbirdio/netbird/management/server/networks/types"
"github.com/netbirdio/netbird/management/server/permissions" "github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/status"
"github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/store"
) )
@@ -25,6 +25,7 @@ type Manager interface {
} }
type managerImpl struct { type managerImpl struct {
core.BaseManager
store store.Store store store.Store
accountManager account.AccountManager accountManager account.AccountManager
permissionsManager permissions.Manager permissionsManager permissions.Manager
@@ -37,33 +38,28 @@ type mockManager struct {
func NewManager(store store.Store, permissionsManager permissions.Manager, resourceManager resources.Manager, routersManager routers.Manager, accountManager account.AccountManager) Manager { func NewManager(store store.Store, permissionsManager permissions.Manager, resourceManager resources.Manager, routersManager routers.Manager, accountManager account.AccountManager) Manager {
return &managerImpl{ return &managerImpl{
store: store, BaseManager: core.NewBaseManager(core.Networks),
permissionsManager: permissionsManager, store: store,
resourcesManager: resourceManager, // permissionsManager: permissionsManager,
routersManager: routersManager, resourcesManager: resourceManager,
accountManager: accountManager, routersManager: routersManager,
accountManager: accountManager,
} }
} }
func (m *managerImpl) GetAllNetworks(ctx context.Context, accountID, userID string) ([]*types.Network, error) { func (m *managerImpl) GetAllNetworks(ctx context.Context, accountID, userID string) ([]*types.Network, error) {
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read) err := m.ValidatePermissions(ctx, core.Read)
if err != nil { if err != nil {
return nil, status.NewPermissionValidationError(err) return nil, err
}
if !ok {
return nil, status.NewPermissionDeniedError()
} }
return m.store.GetAccountNetworks(ctx, store.LockingStrengthShare, accountID) return m.store.GetAccountNetworks(ctx, store.LockingStrengthShare, accountID)
} }
func (m *managerImpl) CreateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) { func (m *managerImpl) CreateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) {
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, network.AccountID, userID, permissions.Networks, permissions.Write) err := m.ValidatePermissions(ctx, core.Write)
if err != nil { if err != nil {
return nil, status.NewPermissionValidationError(err) return nil, err
}
if !ok {
return nil, status.NewPermissionDeniedError()
} }
network.ID = xid.New().String() network.ID = xid.New().String()
@@ -82,24 +78,18 @@ func (m *managerImpl) CreateNetwork(ctx context.Context, userID string, network
} }
func (m *managerImpl) GetNetwork(ctx context.Context, accountID, userID, networkID string) (*types.Network, error) { func (m *managerImpl) GetNetwork(ctx context.Context, accountID, userID, networkID string) (*types.Network, error) {
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read) err := m.ValidatePermissions(ctx, core.Read)
if err != nil { if err != nil {
return nil, status.NewPermissionValidationError(err) return nil, err
}
if !ok {
return nil, status.NewPermissionDeniedError()
} }
return m.store.GetNetworkByID(ctx, store.LockingStrengthShare, accountID, networkID) return m.store.GetNetworkByID(ctx, store.LockingStrengthShare, accountID, networkID)
} }
func (m *managerImpl) UpdateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) { func (m *managerImpl) UpdateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) {
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, network.AccountID, userID, permissions.Networks, permissions.Write) err := m.ValidatePermissions(ctx, core.Write)
if err != nil { if err != nil {
return nil, status.NewPermissionValidationError(err) return nil, err
}
if !ok {
return nil, status.NewPermissionDeniedError()
} }
unlock := m.store.AcquireWriteLockByUID(ctx, network.AccountID) unlock := m.store.AcquireWriteLockByUID(ctx, network.AccountID)
@@ -116,12 +106,9 @@ func (m *managerImpl) UpdateNetwork(ctx context.Context, userID string, network
} }
func (m *managerImpl) DeleteNetwork(ctx context.Context, accountID, userID, networkID string) error { func (m *managerImpl) DeleteNetwork(ctx context.Context, accountID, userID, networkID string) error {
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Write) err := m.ValidatePermissions(ctx, core.Write)
if err != nil { if err != nil {
return status.NewPermissionValidationError(err) return err
}
if !ok {
return status.NewPermissionDeniedError()
} }
network, err := m.store.GetNetworkByID(ctx, store.LockingStrengthUpdate, accountID, networkID) network, err := m.store.GetNetworkByID(ctx, store.LockingStrengthUpdate, accountID, networkID)

View File

@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
nbcontext "github.com/netbirdio/netbird/management/server/context"
"github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/management/server/groups"
"github.com/netbirdio/netbird/management/server/mock_server" "github.com/netbirdio/netbird/management/server/mock_server"
"github.com/netbirdio/netbird/management/server/networks/resources" "github.com/netbirdio/netbird/management/server/networks/resources"
@@ -25,6 +26,7 @@ func Test_GetAllNetworksReturnsNetworks(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
t.Cleanup(cleanUp) t.Cleanup(cleanUp)
am := mock_server.MockAccountManager{} am := mock_server.MockAccountManager{}
permissionsManager := permissions.NewManagerMock() permissionsManager := permissions.NewManagerMock()
groupsManager := groups.NewManagerMock() groupsManager := groups.NewManagerMock()
@@ -32,6 +34,7 @@ func Test_GetAllNetworksReturnsNetworks(t *testing.T) {
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am) resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
manager := NewManager(s, permissionsManager, resourcesManager, routerManager, &am) manager := NewManager(s, permissionsManager, resourcesManager, routerManager, &am)
ctx = nbcontext.SetUserAuthInContext(ctx, nbcontext.UserAuth{AccountId: accountID, UserId: userID})
networks, err := manager.GetAllNetworks(ctx, accountID, userID) networks, err := manager.GetAllNetworks(ctx, accountID, userID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, networks, 1) require.Len(t, networks, 1)

View File

@@ -371,6 +371,9 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer
eventsToStore, err = deletePeers(ctx, am, transaction, accountID, userID, []*nbpeer.Peer{peer}) eventsToStore, err = deletePeers(ctx, am, transaction, accountID, userID, []*nbpeer.Peer{peer})
return err return err
}) })
if err != nil {
return err
}
for _, storeEvent := range eventsToStore { for _, storeEvent := range eventsToStore {
storeEvent() storeEvent()