mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-05 21:19:08 +02:00
Merge branch 'main' into sync-tag-dashboard
This commit is contained in:
@@ -91,6 +91,13 @@ type Options struct {
|
|||||||
// when the embedded client must never act as a stepping stone into
|
// when the embedded client must never act as a stepping stone into
|
||||||
// the host's local network (e.g. the proxy's overlay peer).
|
// the host's local network (e.g. the proxy's overlay peer).
|
||||||
BlockLANAccess bool
|
BlockLANAccess bool
|
||||||
|
// LazyConnectionEnabled is a tri-state local override for lazy connections,
|
||||||
|
// mirroring the NB_LAZY_CONN env var. Nil defers to the management feature
|
||||||
|
// flag; a set value overrides it in both directions. A short-lived client
|
||||||
|
// that reaches only a few known peers can set this to false, so its peers
|
||||||
|
// connect eagerly and the first request does not wait for the connection to
|
||||||
|
// be established.
|
||||||
|
LazyConnectionEnabled *bool
|
||||||
// WireguardPort is the port for the tunnel interface. Use 0 for a random port.
|
// WireguardPort is the port for the tunnel interface. Use 0 for a random port.
|
||||||
WireguardPort *int
|
WireguardPort *int
|
||||||
// MTU is the MTU for the tunnel interface.
|
// MTU is the MTU for the tunnel interface.
|
||||||
@@ -220,6 +227,15 @@ func New(opts Options) (*Client, error) {
|
|||||||
config.PrivateKey = opts.PrivateKey
|
config.PrivateKey = opts.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.LazyConnectionEnabled != nil {
|
||||||
|
// Runtime-only override, read back through lazyconn.ParseState; a set value
|
||||||
|
// wins over the management feature flag in both directions.
|
||||||
|
config.LazyConnection = "off"
|
||||||
|
if *opts.LazyConnectionEnabled {
|
||||||
|
config.LazyConnection = "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if opts.Performance.PreallocatedBuffersPerPool != nil {
|
if opts.Performance.PreallocatedBuffersPerPool != nil {
|
||||||
wgdevice.SetPreallocatedBuffersPerPool(*opts.Performance.PreallocatedBuffersPerPool)
|
wgdevice.SetPreallocatedBuffersPerPool(*opts.Performance.PreallocatedBuffersPerPool)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func UpdateStaticInfoAsync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetInfo retrieves system information for WASM environment
|
// GetInfo retrieves system information for WASM environment
|
||||||
func GetInfo(_ context.Context) *Info {
|
func GetInfo(ctx context.Context) *Info {
|
||||||
info := &Info{
|
info := &Info{
|
||||||
GoOS: runtime.GOOS,
|
GoOS: runtime.GOOS,
|
||||||
Kernel: runtime.GOARCH,
|
Kernel: runtime.GOARCH,
|
||||||
@@ -30,6 +30,13 @@ func GetInfo(_ context.Context) *Info {
|
|||||||
collectBrowserInfo(info)
|
collectBrowserInfo(info)
|
||||||
collectLocationInfo(info)
|
collectLocationInfo(info)
|
||||||
collectSystemInfo(info)
|
collectSystemInfo(info)
|
||||||
|
|
||||||
|
// A caller-provided device name wins, as on the other platforms. A peer
|
||||||
|
// registered over an API keeps reporting the name it was registered with,
|
||||||
|
// so its meta does not change on the first sync.
|
||||||
|
if name := extractDeviceName(ctx, info.Hostname); name != "" {
|
||||||
|
info.Hostname = name
|
||||||
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//go:build js
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestGetInfoHonorsDeviceName covers a caller-provided device name reaching the
|
||||||
|
// reported hostname, so a peer registered over an API keeps reporting the name
|
||||||
|
// it was registered with instead of renaming itself on its first sync.
|
||||||
|
func TestGetInfoHonorsDeviceName(t *testing.T) {
|
||||||
|
ctx := context.WithValue(context.Background(), DeviceNameCtxKey, "session-name")
|
||||||
|
if got := GetInfo(ctx).Hostname; got != "session-name" {
|
||||||
|
t.Errorf("hostname should carry the caller's device name, got %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGetInfoWithoutDeviceNameKeepsFallback covers the embed layer's habit of
|
||||||
|
// always setting the context value: an empty name must not blank the hostname.
|
||||||
|
func TestGetInfoWithoutDeviceNameKeepsFallback(t *testing.T) {
|
||||||
|
ctx := context.WithValue(context.Background(), DeviceNameCtxKey, "")
|
||||||
|
if got := GetInfo(ctx).Hostname; got == "" {
|
||||||
|
t.Error("an empty device name must not blank the hostname")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build windows || (linux && !android) || (darwin && !ios) || freebsd
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
+31
-4
@@ -56,8 +56,7 @@ func startClient(ctx context.Context, nbClient *netbird.Client) error {
|
|||||||
// parseClientOptions extracts NetBird options from JavaScript object
|
// parseClientOptions extracts NetBird options from JavaScript object
|
||||||
func parseClientOptions(jsOptions js.Value) (netbird.Options, error) {
|
func parseClientOptions(jsOptions js.Value) (netbird.Options, error) {
|
||||||
options := netbird.Options{
|
options := netbird.Options{
|
||||||
DeviceName: "dashboard-client",
|
LogLevel: defaultLogLevel,
|
||||||
LogLevel: defaultLogLevel,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if jwtToken := jsOptions.Get("jwtToken"); !jwtToken.IsNull() && !jwtToken.IsUndefined() {
|
if jwtToken := jsOptions.Get("jwtToken"); !jwtToken.IsNull() && !jwtToken.IsUndefined() {
|
||||||
@@ -87,13 +86,41 @@ func parseClientOptions(jsOptions js.Value) (netbird.Options, error) {
|
|||||||
options.DeviceName = deviceName.String()
|
options.DeviceName = deviceName.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if disableIPv6 := jsOptions.Get("disableIPv6"); !disableIPv6.IsNull() && !disableIPv6.IsUndefined() {
|
disableIPv6, err := boolOption(jsOptions, "disableIPv6")
|
||||||
options.DisableIPv6 = disableIPv6.Bool()
|
if err != nil {
|
||||||
|
return options, err
|
||||||
|
}
|
||||||
|
if disableIPv6 != nil {
|
||||||
|
options.DisableIPv6 = *disableIPv6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The caller decides whether this client uses lazy connections; left unset it
|
||||||
|
// defers to the management feature flag. A short-lived, interactive caller
|
||||||
|
// turns it off so its sessions reach the few peers their grant covers eagerly,
|
||||||
|
// instead of the first request waiting for the connection to be established.
|
||||||
|
lazyConnectionEnabled, err := boolOption(jsOptions, "lazyConnectionEnabled")
|
||||||
|
if err != nil {
|
||||||
|
return options, err
|
||||||
|
}
|
||||||
|
options.LazyConnectionEnabled = lazyConnectionEnabled
|
||||||
|
|
||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// boolOption reads a boolean option, returning nil when the caller left it out.
|
||||||
|
// js.Value.Bool panics on any other type, so a wrong type is reported instead.
|
||||||
|
func boolOption(jsOptions js.Value, name string) (*bool, error) {
|
||||||
|
v := jsOptions.Get(name)
|
||||||
|
if v.IsNull() || v.IsUndefined() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if v.Type() != js.TypeBoolean {
|
||||||
|
return nil, fmt.Errorf("option %s must be a boolean, got %s", name, v.Type())
|
||||||
|
}
|
||||||
|
b := v.Bool()
|
||||||
|
return &b, nil
|
||||||
|
}
|
||||||
|
|
||||||
// createStartMethod creates the start method for the client
|
// createStartMethod creates the start method for the client
|
||||||
func createStartMethod(client *netbird.Client) js.Func {
|
func createStartMethod(client *netbird.Client) js.Func {
|
||||||
return js.FuncOf(func(this js.Value, args []js.Value) any {
|
return js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
//go:build js
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall/js"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestParseClientOptionsBooleans covers the boolean options against the value
|
||||||
|
// kinds a JS caller can pass: js.Value.Bool panics on anything but a boolean,
|
||||||
|
// so a wrong type has to be rejected before it reaches the client.
|
||||||
|
func TestParseClientOptionsBooleans(t *testing.T) {
|
||||||
|
t.Run("unset leaves the lazy override empty", func(t *testing.T) {
|
||||||
|
options, err := parseClientOptions(js.Global().Get("Object").New())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse options: %v", err)
|
||||||
|
}
|
||||||
|
if options.LazyConnectionEnabled != nil {
|
||||||
|
t.Errorf("lazy override should stay unset, got %v", *options.LazyConnectionEnabled)
|
||||||
|
}
|
||||||
|
if options.DisableIPv6 {
|
||||||
|
t.Error("disableIPv6 should default to false")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("null defers to the management flag", func(t *testing.T) {
|
||||||
|
jsOptions := js.Global().Get("Object").New()
|
||||||
|
jsOptions.Set("lazyConnectionEnabled", js.Null())
|
||||||
|
options, err := parseClientOptions(jsOptions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse options: %v", err)
|
||||||
|
}
|
||||||
|
if options.LazyConnectionEnabled != nil {
|
||||||
|
t.Errorf("lazy override should stay unset, got %v", *options.LazyConnectionEnabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("booleans are carried through", func(t *testing.T) {
|
||||||
|
jsOptions := js.Global().Get("Object").New()
|
||||||
|
jsOptions.Set("lazyConnectionEnabled", false)
|
||||||
|
jsOptions.Set("disableIPv6", true)
|
||||||
|
options, err := parseClientOptions(jsOptions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse options: %v", err)
|
||||||
|
}
|
||||||
|
if options.LazyConnectionEnabled == nil || *options.LazyConnectionEnabled {
|
||||||
|
t.Errorf("lazy override should be false, got %v", options.LazyConnectionEnabled)
|
||||||
|
}
|
||||||
|
if !options.DisableIPv6 {
|
||||||
|
t.Error("disableIPv6 should be true")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("a non-boolean is rejected", func(t *testing.T) {
|
||||||
|
for _, value := range []any{"true", 1, js.Global().Get("Object").New()} {
|
||||||
|
jsOptions := js.Global().Get("Object").New()
|
||||||
|
jsOptions.Set("lazyConnectionEnabled", value)
|
||||||
|
if _, err := parseClientOptions(jsOptions); err == nil {
|
||||||
|
t.Errorf("value %v should be rejected", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user