mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-19 08:46:38 +00:00
Merge branch 'main' into fix/login-filter
This commit is contained in:
@@ -59,6 +59,8 @@ type Client struct {
|
|||||||
deviceName string
|
deviceName string
|
||||||
uiVersion string
|
uiVersion string
|
||||||
networkChangeListener listener.NetworkChangeListener
|
networkChangeListener listener.NetworkChangeListener
|
||||||
|
|
||||||
|
connectClient *internal.ConnectClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient instantiate a new Client
|
// NewClient instantiate a new Client
|
||||||
@@ -106,8 +108,8 @@ func (c *Client) Run(urlOpener URLOpener, dns *DNSList, dnsReadyListener DnsRead
|
|||||||
|
|
||||||
// todo do not throw error in case of cancelled context
|
// todo do not throw error in case of cancelled context
|
||||||
ctx = internal.CtxInitState(ctx)
|
ctx = internal.CtxInitState(ctx)
|
||||||
connectClient := internal.NewConnectClient(ctx, cfg, c.recorder)
|
c.connectClient = internal.NewConnectClient(ctx, cfg, c.recorder)
|
||||||
return connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, dns.items, dnsReadyListener)
|
return c.connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, dns.items, dnsReadyListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunWithoutLogin we apply this type of run function when the backed has been started without UI (i.e. after reboot).
|
// RunWithoutLogin we apply this type of run function when the backed has been started without UI (i.e. after reboot).
|
||||||
@@ -132,8 +134,8 @@ func (c *Client) RunWithoutLogin(dns *DNSList, dnsReadyListener DnsReadyListener
|
|||||||
|
|
||||||
// todo do not throw error in case of cancelled context
|
// todo do not throw error in case of cancelled context
|
||||||
ctx = internal.CtxInitState(ctx)
|
ctx = internal.CtxInitState(ctx)
|
||||||
connectClient := internal.NewConnectClient(ctx, cfg, c.recorder)
|
c.connectClient = internal.NewConnectClient(ctx, cfg, c.recorder)
|
||||||
return connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, dns.items, dnsReadyListener)
|
return c.connectClient.RunOnAndroid(c.tunAdapter, c.iFaceDiscover, c.networkChangeListener, dns.items, dnsReadyListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the internal client and free the resources
|
// Stop the internal client and free the resources
|
||||||
@@ -174,6 +176,53 @@ func (c *Client) PeersList() *PeerInfoArray {
|
|||||||
return &PeerInfoArray{items: peerInfos}
|
return &PeerInfoArray{items: peerInfos}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Networks() *NetworkArray {
|
||||||
|
if c.connectClient == nil {
|
||||||
|
log.Error("not connected")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
engine := c.connectClient.Engine()
|
||||||
|
if engine == nil {
|
||||||
|
log.Error("could not get engine")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
routeManager := engine.GetRouteManager()
|
||||||
|
if routeManager == nil {
|
||||||
|
log.Error("could not get route manager")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
networkArray := &NetworkArray{
|
||||||
|
items: make([]Network, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, routes := range routeManager.GetClientRoutesWithNetID() {
|
||||||
|
if len(routes) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if routes[0].IsDynamic() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := c.recorder.GetPeer(routes[0].Peer)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("could not get peer info for %s: %v", routes[0].Peer, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
network := Network{
|
||||||
|
Name: string(id),
|
||||||
|
Network: routes[0].Network.String(),
|
||||||
|
Peer: peer.FQDN,
|
||||||
|
Status: peer.ConnStatus.String(),
|
||||||
|
}
|
||||||
|
networkArray.Add(network)
|
||||||
|
}
|
||||||
|
return networkArray
|
||||||
|
}
|
||||||
|
|
||||||
// OnUpdatedHostDNS update the DNS servers addresses for root zones
|
// OnUpdatedHostDNS update the DNS servers addresses for root zones
|
||||||
func (c *Client) OnUpdatedHostDNS(list *DNSList) error {
|
func (c *Client) OnUpdatedHostDNS(list *DNSList) error {
|
||||||
dnsServer, err := dns.GetServerDns()
|
dnsServer, err := dns.GetServerDns()
|
||||||
|
|||||||
27
client/android/networks.go
Normal file
27
client/android/networks.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//go:build android
|
||||||
|
|
||||||
|
package android
|
||||||
|
|
||||||
|
type Network struct {
|
||||||
|
Name string
|
||||||
|
Network string
|
||||||
|
Peer string
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkArray struct {
|
||||||
|
items []Network
|
||||||
|
}
|
||||||
|
|
||||||
|
func (array *NetworkArray) Add(s Network) *NetworkArray {
|
||||||
|
array.items = append(array.items, s)
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
|
func (array *NetworkArray) Get(i int) *Network {
|
||||||
|
return &array.items[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (array *NetworkArray) Size() int {
|
||||||
|
return len(array.items)
|
||||||
|
}
|
||||||
@@ -7,30 +7,23 @@ type PeerInfo struct {
|
|||||||
ConnStatus string // Todo replace to enum
|
ConnStatus string // Todo replace to enum
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerInfoCollection made for Java layer to get non default types as collection
|
// PeerInfoArray is a wrapper of []PeerInfo
|
||||||
type PeerInfoCollection interface {
|
|
||||||
Add(s string) PeerInfoCollection
|
|
||||||
Get(i int) string
|
|
||||||
Size() int
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerInfoArray is the implementation of the PeerInfoCollection
|
|
||||||
type PeerInfoArray struct {
|
type PeerInfoArray struct {
|
||||||
items []PeerInfo
|
items []PeerInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new PeerInfo to the collection
|
// Add new PeerInfo to the collection
|
||||||
func (array PeerInfoArray) Add(s PeerInfo) PeerInfoArray {
|
func (array *PeerInfoArray) Add(s PeerInfo) *PeerInfoArray {
|
||||||
array.items = append(array.items, s)
|
array.items = append(array.items, s)
|
||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get return an element of the collection
|
// Get return an element of the collection
|
||||||
func (array PeerInfoArray) Get(i int) *PeerInfo {
|
func (array *PeerInfoArray) Get(i int) *PeerInfo {
|
||||||
return &array.items[i]
|
return &array.items[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size return with the size of the collection
|
// Size return with the size of the collection
|
||||||
func (array PeerInfoArray) Size() int {
|
func (array *PeerInfoArray) Size() int {
|
||||||
return len(array.items)
|
return len(array.items)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ func statusFunc(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.GetStatus() == string(internal.StatusNeedsLogin) || resp.GetStatus() == string(internal.StatusLoginFailed) {
|
status := resp.GetStatus()
|
||||||
|
|
||||||
|
if status == string(internal.StatusNeedsLogin) || status == string(internal.StatusLoginFailed) ||
|
||||||
|
status == string(internal.StatusSessionExpired) {
|
||||||
cmd.Printf("Daemon status: %s\n\n"+
|
cmd.Printf("Daemon status: %s\n\n"+
|
||||||
"Run UP command to log in with SSO (interactive login):\n\n"+
|
"Run UP command to log in with SSO (interactive login):\n\n"+
|
||||||
" netbird up \n\n"+
|
" netbird up \n\n"+
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ type StatusType string
|
|||||||
const (
|
const (
|
||||||
StatusIdle StatusType = "Idle"
|
StatusIdle StatusType = "Idle"
|
||||||
|
|
||||||
StatusConnecting StatusType = "Connecting"
|
StatusConnecting StatusType = "Connecting"
|
||||||
StatusConnected StatusType = "Connected"
|
StatusConnected StatusType = "Connected"
|
||||||
StatusNeedsLogin StatusType = "NeedsLogin"
|
StatusNeedsLogin StatusType = "NeedsLogin"
|
||||||
StatusLoginFailed StatusType = "LoginFailed"
|
StatusLoginFailed StatusType = "LoginFailed"
|
||||||
|
StatusSessionExpired StatusType = "SessionExpired"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CtxInitState setup context state into the context tree.
|
// CtxInitState setup context state into the context tree.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
@@ -66,6 +67,7 @@ type Server struct {
|
|||||||
|
|
||||||
lastProbe time.Time
|
lastProbe time.Time
|
||||||
persistNetworkMap bool
|
persistNetworkMap bool
|
||||||
|
isSessionActive atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type oauthAuthFlow struct {
|
type oauthAuthFlow struct {
|
||||||
@@ -567,9 +569,6 @@ func (s *Server) WaitSSOLogin(callerCtx context.Context, msg *proto.WaitSSOLogin
|
|||||||
|
|
||||||
tokenInfo, err := s.oauthAuthFlow.flow.WaitToken(waitCTX, flowInfo)
|
tokenInfo, err := s.oauthAuthFlow.flow.WaitToken(waitCTX, flowInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == context.Canceled {
|
|
||||||
return nil, nil //nolint:nilnil
|
|
||||||
}
|
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
s.oauthAuthFlow.expiresAt = time.Now()
|
s.oauthAuthFlow.expiresAt = time.Now()
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
@@ -640,6 +639,7 @@ func (s *Server) Up(callerCtx context.Context, _ *proto.UpRequest) (*proto.UpRes
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-runningChan:
|
case <-runningChan:
|
||||||
|
s.isSessionActive.Store(true)
|
||||||
return &proto.UpResponse{}, nil
|
return &proto.UpResponse{}, nil
|
||||||
case <-callerCtx.Done():
|
case <-callerCtx.Done():
|
||||||
log.Debug("context done, stopping the wait for engine to become ready")
|
log.Debug("context done, stopping the wait for engine to become ready")
|
||||||
@@ -668,6 +668,7 @@ func (s *Server) Down(ctx context.Context, _ *proto.DownRequest) (*proto.DownRes
|
|||||||
log.Errorf("failed to shut down properly: %v", err)
|
log.Errorf("failed to shut down properly: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
s.isSessionActive.Store(false)
|
||||||
|
|
||||||
state := internal.CtxGetState(s.rootCtx)
|
state := internal.CtxGetState(s.rootCtx)
|
||||||
state.Set(internal.StatusIdle)
|
state.Set(internal.StatusIdle)
|
||||||
@@ -694,6 +695,12 @@ func (s *Server) Status(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if status == internal.StatusNeedsLogin && s.isSessionActive.Load() {
|
||||||
|
log.Debug("status requested while session is active, returning SessionExpired")
|
||||||
|
status = internal.StatusSessionExpired
|
||||||
|
s.isSessionActive.Store(false)
|
||||||
|
}
|
||||||
|
|
||||||
statusResponse := proto.StatusResponse{Status: string(status), DaemonVersion: version.NetbirdVersion()}
|
statusResponse := proto.StatusResponse{Status: string(status), DaemonVersion: version.NetbirdVersion()}
|
||||||
|
|
||||||
s.statusRecorder.UpdateManagementAddress(s.config.ManagementURL.String())
|
s.statusRecorder.UpdateManagementAddress(s.config.ManagementURL.String())
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ import (
|
|||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/app"
|
"fyne.io/fyne/v2/app"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
"fyne.io/fyne/v2/dialog"
|
"fyne.io/fyne/v2/dialog"
|
||||||
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"fyne.io/systray"
|
"fyne.io/systray"
|
||||||
@@ -51,7 +54,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
daemonAddr, showSettings, showNetworks, showDebug, errorMsg, saveLogsInFile := parseFlags()
|
daemonAddr, showSettings, showNetworks, showLoginURL, showDebug, errorMsg, saveLogsInFile := parseFlags()
|
||||||
|
|
||||||
// Initialize file logging if needed.
|
// Initialize file logging if needed.
|
||||||
var logFile string
|
var logFile string
|
||||||
@@ -77,13 +80,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the service client (this also builds the settings or networks UI if requested).
|
// Create the service client (this also builds the settings or networks UI if requested).
|
||||||
client := newServiceClient(daemonAddr, logFile, a, showSettings, showNetworks, showDebug)
|
client := newServiceClient(daemonAddr, logFile, a, showSettings, showNetworks, showLoginURL, showDebug)
|
||||||
|
|
||||||
// Watch for theme/settings changes to update the icon.
|
// Watch for theme/settings changes to update the icon.
|
||||||
go watchSettingsChanges(a, client)
|
go watchSettingsChanges(a, client)
|
||||||
|
|
||||||
// Run in window mode if any UI flag was set.
|
// Run in window mode if any UI flag was set.
|
||||||
if showSettings || showNetworks || showDebug {
|
if showSettings || showNetworks || showDebug || showLoginURL {
|
||||||
a.Run()
|
a.Run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseFlags reads and returns all needed command-line flags.
|
// parseFlags reads and returns all needed command-line flags.
|
||||||
func parseFlags() (daemonAddr string, showSettings, showNetworks, showDebug bool, errorMsg string, saveLogsInFile bool) {
|
func parseFlags() (daemonAddr string, showSettings, showNetworks, showLoginURL, showDebug bool, errorMsg string, saveLogsInFile bool) {
|
||||||
defaultDaemonAddr := "unix:///var/run/netbird.sock"
|
defaultDaemonAddr := "unix:///var/run/netbird.sock"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
defaultDaemonAddr = "tcp://127.0.0.1:41731"
|
defaultDaemonAddr = "tcp://127.0.0.1:41731"
|
||||||
@@ -112,6 +115,7 @@ func parseFlags() (daemonAddr string, showSettings, showNetworks, showDebug bool
|
|||||||
flag.StringVar(&daemonAddr, "daemon-addr", defaultDaemonAddr, "Daemon service address to serve CLI requests [unix|tcp]://[path|host:port]")
|
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(&showSettings, "settings", false, "run settings window")
|
||||||
flag.BoolVar(&showNetworks, "networks", false, "run networks window")
|
flag.BoolVar(&showNetworks, "networks", false, "run networks window")
|
||||||
|
flag.BoolVar(&showLoginURL, "login-url", false, "show login URL in a popup window")
|
||||||
flag.BoolVar(&showDebug, "debug", false, "run debug window")
|
flag.BoolVar(&showDebug, "debug", false, "run debug window")
|
||||||
flag.StringVar(&errorMsg, "error-msg", "", "displays an error message window")
|
flag.StringVar(&errorMsg, "error-msg", "", "displays an error message window")
|
||||||
flag.BoolVar(&saveLogsInFile, "use-log-file", false, fmt.Sprintf("save logs in a file: %s/netbird-ui-PID.log", os.TempDir()))
|
flag.BoolVar(&saveLogsInFile, "use-log-file", false, fmt.Sprintf("save logs in a file: %s/netbird-ui-PID.log", os.TempDir()))
|
||||||
@@ -253,6 +257,7 @@ type serviceClient struct {
|
|||||||
exitNodeStates []exitNodeState
|
exitNodeStates []exitNodeState
|
||||||
mExitNodeDeselectAll *systray.MenuItem
|
mExitNodeDeselectAll *systray.MenuItem
|
||||||
logFile string
|
logFile string
|
||||||
|
wLoginURL fyne.Window
|
||||||
}
|
}
|
||||||
|
|
||||||
type menuHandler struct {
|
type menuHandler struct {
|
||||||
@@ -263,7 +268,7 @@ type menuHandler struct {
|
|||||||
// newServiceClient instance constructor
|
// newServiceClient instance constructor
|
||||||
//
|
//
|
||||||
// This constructor also builds the UI elements for the settings window.
|
// This constructor also builds the UI elements for the settings window.
|
||||||
func newServiceClient(addr string, logFile string, a fyne.App, showSettings bool, showNetworks bool, showDebug bool) *serviceClient {
|
func newServiceClient(addr string, logFile string, a fyne.App, showSettings bool, showNetworks bool, showLoginURL bool, showDebug bool) *serviceClient {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
s := &serviceClient{
|
s := &serviceClient{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -286,6 +291,8 @@ func newServiceClient(addr string, logFile string, a fyne.App, showSettings bool
|
|||||||
s.showSettingsUI()
|
s.showSettingsUI()
|
||||||
case showNetworks:
|
case showNetworks:
|
||||||
s.showNetworksUI()
|
s.showNetworksUI()
|
||||||
|
case showLoginURL:
|
||||||
|
s.showLoginURL()
|
||||||
case showDebug:
|
case showDebug:
|
||||||
s.showDebugUI()
|
s.showDebugUI()
|
||||||
}
|
}
|
||||||
@@ -445,11 +452,11 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceClient) login() error {
|
func (s *serviceClient) login(openURL bool) (*proto.LoginResponse, error) {
|
||||||
conn, err := s.getSrvClient(defaultFailTimeout)
|
conn, err := s.getSrvClient(defaultFailTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("get client: %v", err)
|
log.Errorf("get client: %v", err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
loginResp, err := conn.Login(s.ctx, &proto.LoginRequest{
|
loginResp, err := conn.Login(s.ctx, &proto.LoginRequest{
|
||||||
@@ -457,24 +464,24 @@ func (s *serviceClient) login() error {
|
|||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("login to management URL with: %v", err)
|
log.Errorf("login to management URL with: %v", err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if loginResp.NeedsSSOLogin {
|
if loginResp.NeedsSSOLogin && openURL {
|
||||||
err = open.Run(loginResp.VerificationURIComplete)
|
err = open.Run(loginResp.VerificationURIComplete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("opening the verification uri in the browser failed: %v", err)
|
log.Errorf("opening the verification uri in the browser failed: %v", err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.WaitSSOLogin(s.ctx, &proto.WaitSSOLoginRequest{UserCode: loginResp.UserCode})
|
_, err = conn.WaitSSOLogin(s.ctx, &proto.WaitSSOLoginRequest{UserCode: loginResp.UserCode})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("waiting sso login failed with: %v", err)
|
log.Errorf("waiting sso login failed with: %v", err)
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return loginResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceClient) menuUpClick() error {
|
func (s *serviceClient) menuUpClick() error {
|
||||||
@@ -486,7 +493,7 @@ func (s *serviceClient) menuUpClick() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.login()
|
_, err = s.login(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("login failed with: %v", err)
|
log.Errorf("login failed with: %v", err)
|
||||||
return err
|
return err
|
||||||
@@ -558,14 +565,14 @@ func (s *serviceClient) updateStatus() error {
|
|||||||
defer s.updateIndicationLock.Unlock()
|
defer s.updateIndicationLock.Unlock()
|
||||||
|
|
||||||
// notify the user when the session has expired
|
// notify the user when the session has expired
|
||||||
if status.Status == string(internal.StatusNeedsLogin) {
|
if status.Status == string(internal.StatusSessionExpired) {
|
||||||
s.onSessionExpire()
|
s.onSessionExpire()
|
||||||
}
|
}
|
||||||
|
|
||||||
var systrayIconState bool
|
var systrayIconState bool
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case status.Status == string(internal.StatusConnected):
|
case status.Status == string(internal.StatusConnected) && !s.mUp.Disabled():
|
||||||
s.connected = true
|
s.connected = true
|
||||||
s.sendNotification = true
|
s.sendNotification = true
|
||||||
if s.isUpdateIconActive {
|
if s.isUpdateIconActive {
|
||||||
@@ -732,7 +739,6 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
go s.eventHandler.listen(s.ctx)
|
go s.eventHandler.listen(s.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *serviceClient) attachOutput(cmd *exec.Cmd) *os.File {
|
func (s *serviceClient) attachOutput(cmd *exec.Cmd) *os.File {
|
||||||
if s.logFile == "" {
|
if s.logFile == "" {
|
||||||
// attach child's streams to parent's streams
|
// attach child's streams to parent's streams
|
||||||
@@ -871,17 +877,9 @@ func (s *serviceClient) onUpdateAvailable() {
|
|||||||
|
|
||||||
// onSessionExpire sends a notification to the user when the session expires.
|
// onSessionExpire sends a notification to the user when the session expires.
|
||||||
func (s *serviceClient) onSessionExpire() {
|
func (s *serviceClient) onSessionExpire() {
|
||||||
|
s.sendNotification = true
|
||||||
if s.sendNotification {
|
if s.sendNotification {
|
||||||
title := "Connection session expired"
|
s.eventHandler.runSelfCommand("login-url", "true")
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
title = "NetBird connection session expired"
|
|
||||||
}
|
|
||||||
s.app.SendNotification(
|
|
||||||
fyne.NewNotification(
|
|
||||||
title,
|
|
||||||
"Please re-authenticate to connect to the network",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
s.sendNotification = false
|
s.sendNotification = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -955,9 +953,9 @@ func (s *serviceClient) updateConfig() error {
|
|||||||
ServerSSHAllowed: &sshAllowed,
|
ServerSSHAllowed: &sshAllowed,
|
||||||
RosenpassEnabled: &rosenpassEnabled,
|
RosenpassEnabled: &rosenpassEnabled,
|
||||||
DisableAutoConnect: &disableAutoStart,
|
DisableAutoConnect: &disableAutoStart,
|
||||||
|
DisableNotifications: ¬ificationsDisabled,
|
||||||
LazyConnectionEnabled: &lazyConnectionEnabled,
|
LazyConnectionEnabled: &lazyConnectionEnabled,
|
||||||
BlockInbound: &blockInbound,
|
BlockInbound: &blockInbound,
|
||||||
DisableNotifications: ¬ificationsDisabled,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.restartClient(&loginRequest); err != nil {
|
if err := s.restartClient(&loginRequest); err != nil {
|
||||||
@@ -991,6 +989,87 @@ func (s *serviceClient) restartClient(loginRequest *proto.LoginRequest) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// showLoginURL creates a borderless window styled like a pop-up in the top-right corner using s.wLoginURL.
|
||||||
|
func (s *serviceClient) showLoginURL() {
|
||||||
|
|
||||||
|
resp, err := s.login(false)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to fetch login URL: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verificationURL := resp.VerificationURIComplete
|
||||||
|
if verificationURL == "" {
|
||||||
|
verificationURL = resp.VerificationURI
|
||||||
|
}
|
||||||
|
|
||||||
|
if verificationURL == "" {
|
||||||
|
log.Error("no verification URL provided in the login response")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resIcon := fyne.NewStaticResource("netbird.png", iconAbout)
|
||||||
|
|
||||||
|
if s.wLoginURL == nil {
|
||||||
|
s.wLoginURL = s.app.NewWindow("NetBird Session Expired")
|
||||||
|
s.wLoginURL.Resize(fyne.NewSize(400, 200))
|
||||||
|
s.wLoginURL.SetIcon(resIcon)
|
||||||
|
}
|
||||||
|
// add a description label
|
||||||
|
label := widget.NewLabel("Your NetBird session has expired.\nPlease re-authenticate to continue using NetBird.")
|
||||||
|
|
||||||
|
btn := widget.NewButtonWithIcon("Re-authenticate", theme.ViewRefreshIcon(), func() {
|
||||||
|
|
||||||
|
conn, err := s.getSrvClient(defaultFailTimeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("get client: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := openURL(verificationURL); err != nil {
|
||||||
|
log.Errorf("failed to open login URL: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = conn.WaitSSOLogin(s.ctx, &proto.WaitSSOLoginRequest{UserCode: resp.UserCode})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Waiting sso login failed with: %v", err)
|
||||||
|
label.SetText("Waiting login failed, please create \na debug bundle in the settings and contact support.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
label.SetText("Re-authentication successful.\nReconnecting")
|
||||||
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
_, err = conn.Up(s.ctx, &proto.UpRequest{})
|
||||||
|
if err != nil {
|
||||||
|
label.SetText("Reconnecting failed, please create \na debug bundle in the settings and contact support.")
|
||||||
|
log.Errorf("Reconnecting failed with: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
label.SetText("Connection successful.\nClosing this window.")
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
s.wLoginURL.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
img := canvas.NewImageFromResource(resIcon)
|
||||||
|
img.FillMode = canvas.ImageFillContain
|
||||||
|
img.SetMinSize(fyne.NewSize(64, 64))
|
||||||
|
img.Resize(fyne.NewSize(64, 64))
|
||||||
|
|
||||||
|
// center the content vertically
|
||||||
|
content := container.NewVBox(
|
||||||
|
layout.NewSpacer(),
|
||||||
|
img,
|
||||||
|
label,
|
||||||
|
btn,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
)
|
||||||
|
s.wLoginURL.SetContent(container.NewCenter(content))
|
||||||
|
|
||||||
|
s.wLoginURL.Show()
|
||||||
|
}
|
||||||
|
|
||||||
func openURL(url string) error {
|
func openURL(url string) error {
|
||||||
var err error
|
var err error
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
|
|||||||
@@ -358,8 +358,6 @@ func (s *serviceClient) updateExitNodes() {
|
|||||||
} else {
|
} else {
|
||||||
s.mExitNode.Disable()
|
s.mExitNode.Disable()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Exit nodes updated: %d", len(s.mExitNodeItems))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceClient) recreateExitNodeMenu(exitNodes []*proto.Network) {
|
func (s *serviceClient) recreateExitNodeMenu(exitNodes []*proto.Network) {
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -63,7 +63,7 @@ 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-20250529122842-6700aa91190c
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250612164546-6bd7e2338d65
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb
|
||||||
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
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -503,8 +503,8 @@ github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944 h1:TDtJKmM6S
|
|||||||
github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944/go.mod h1:sHA6TRxjQ6RLbnI+3R4DZo2Eseg/iKiPRfNmcuNySVQ=
|
github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944/go.mod h1:sHA6TRxjQ6RLbnI+3R4DZo2Eseg/iKiPRfNmcuNySVQ=
|
||||||
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e h1:PURA50S8u4mF6RrkYYCAvvPCixhqqEiEy3Ej6avh04c=
|
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e h1:PURA50S8u4mF6RrkYYCAvvPCixhqqEiEy3Ej6avh04c=
|
||||||
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e/go.mod h1:YMLU7qbKfVjmEv7EoZPIVEI+kNYxWCdPK3VS0BU+U4Q=
|
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e/go.mod h1:YMLU7qbKfVjmEv7EoZPIVEI+kNYxWCdPK3VS0BU+U4Q=
|
||||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20250529122842-6700aa91190c h1:SdZxYjR9XXHLyRsTbS1EHBr6+RI15oie1K9Q8yvi3FY=
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250612164546-6bd7e2338d65 h1:5OfYiLjpr4dbQYJI5ouZaylkVdi2KlErLFOwBeBo5Hw=
|
||||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20250529122842-6700aa91190c/go.mod h1:Gi9raplYzCCyh07Olw/DVfCJTFgpr1WCXJ/Q+8TSA9Q=
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250612164546-6bd7e2338d65/go.mod h1:Gi9raplYzCCyh07Olw/DVfCJTFgpr1WCXJ/Q+8TSA9Q=
|
||||||
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9axERMVN63dqyFqnvuD+EMJHzM7mNGON8=
|
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9axERMVN63dqyFqnvuD+EMJHzM7mNGON8=
|
||||||
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb h1:Cr6age+ePALqlSvtp7wc6lYY97XN7rkD1K4XEDmY+TU=
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb h1:Cr6age+ePALqlSvtp7wc6lYY97XN7rkD1K4XEDmY+TU=
|
||||||
|
|||||||
@@ -159,6 +159,12 @@ var (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
integrationMetrics, err := integrations.InitIntegrationMetrics(ctx, appMetrics)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
store, err := store.NewStore(ctx, config.StoreConfig.Engine, config.Datadir, appMetrics, false)
|
store, err := store.NewStore(ctx, config.StoreConfig.Engine, config.Datadir, appMetrics, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed creating Store: %s: %v", config.Datadir, err)
|
return fmt.Errorf("failed creating Store: %s: %v", config.Datadir, err)
|
||||||
@@ -176,7 +182,7 @@ var (
|
|||||||
if disableSingleAccMode {
|
if disableSingleAccMode {
|
||||||
mgmtSingleAccModeDomain = ""
|
mgmtSingleAccModeDomain = ""
|
||||||
}
|
}
|
||||||
eventStore, key, err := integrations.InitEventStore(ctx, config.Datadir, config.DataStoreEncryptionKey)
|
eventStore, key, err := integrations.InitEventStore(ctx, config.Datadir, config.DataStoreEncryptionKey, integrationMetrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to initialize database: %s", err)
|
return fmt.Errorf("failed to initialize database: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -182,7 +181,7 @@ func TestDefaultAccountManager_CreateSetupKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertKey(t, key, tCase.expectedKeyName, false, tCase.expectedType, tCase.expectedUsedTimes,
|
assertKey(t, key, tCase.expectedKeyName, false, tCase.expectedType, tCase.expectedUsedTimes,
|
||||||
tCase.expectedCreatedAt, tCase.expectedExpiresAt, strconv.Itoa(int(types.Hash(key.Key))),
|
tCase.expectedCreatedAt, tCase.expectedExpiresAt, key.Id,
|
||||||
tCase.expectedUpdatedAt, tCase.expectedGroups, false)
|
tCase.expectedUpdatedAt, tCase.expectedGroups, false)
|
||||||
|
|
||||||
// check the corresponding events that should have been generated
|
// check the corresponding events that should have been generated
|
||||||
@@ -258,10 +257,10 @@ func TestGenerateDefaultSetupKey(t *testing.T) {
|
|||||||
expectedExpiresAt := time.Now().UTC().Add(24 * 30 * time.Hour)
|
expectedExpiresAt := time.Now().UTC().Add(24 * 30 * time.Hour)
|
||||||
var expectedAutoGroups []string
|
var expectedAutoGroups []string
|
||||||
|
|
||||||
key, plainKey := types.GenerateDefaultSetupKey()
|
key, _ := types.GenerateDefaultSetupKey()
|
||||||
|
|
||||||
assertKey(t, key, expectedName, expectedRevoke, expectedType, expectedUsedTimes, expectedCreatedAt,
|
assertKey(t, key, expectedName, expectedRevoke, expectedType, expectedUsedTimes, expectedCreatedAt,
|
||||||
expectedExpiresAt, strconv.Itoa(int(types.Hash(plainKey))), expectedUpdatedAt, expectedAutoGroups, true)
|
expectedExpiresAt, key.Id, expectedUpdatedAt, expectedAutoGroups, true)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,10 +274,10 @@ func TestGenerateSetupKey(t *testing.T) {
|
|||||||
expectedUpdatedAt := time.Now().UTC()
|
expectedUpdatedAt := time.Now().UTC()
|
||||||
var expectedAutoGroups []string
|
var expectedAutoGroups []string
|
||||||
|
|
||||||
key, plain := types.GenerateSetupKey(expectedName, types.SetupKeyOneOff, time.Hour, []string{}, types.SetupKeyUnlimitedUsage, false, false)
|
key, _ := types.GenerateSetupKey(expectedName, types.SetupKeyOneOff, time.Hour, []string{}, types.SetupKeyUnlimitedUsage, false, false)
|
||||||
|
|
||||||
assertKey(t, key, expectedName, expectedRevoke, expectedType, expectedUsedTimes, expectedCreatedAt,
|
assertKey(t, key, expectedName, expectedRevoke, expectedType, expectedUsedTimes, expectedCreatedAt,
|
||||||
expectedExpiresAt, strconv.Itoa(int(types.Hash(plain))), expectedUpdatedAt, expectedAutoGroups, true)
|
expectedExpiresAt, key.Id, expectedUpdatedAt, expectedAutoGroups, true)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,10 +184,10 @@ func (appMetrics *defaultAppMetrics) Expose(ctx context.Context, port int, endpo
|
|||||||
}
|
}
|
||||||
appMetrics.listener = listener
|
appMetrics.listener = listener
|
||||||
go func() {
|
go func() {
|
||||||
err := http.Serve(listener, rootRouter)
|
if err := http.Serve(listener, rootRouter); err != nil && err != http.ErrServerClosed {
|
||||||
if err != nil {
|
log.WithContext(ctx).Errorf("metrics server error: %v", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
log.WithContext(ctx).Info("metrics server stopped")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
log.WithContext(ctx).Infof("enabled application metrics and exposing on http://%s", listener.Addr().String())
|
log.WithContext(ctx).Infof("enabled application metrics and exposing on http://%s", listener.Addr().String())
|
||||||
@@ -204,7 +204,7 @@ func (appMetrics *defaultAppMetrics) GetMeter() metric2.Meter {
|
|||||||
func NewDefaultAppMetrics(ctx context.Context) (AppMetrics, error) {
|
func NewDefaultAppMetrics(ctx context.Context) (AppMetrics, error) {
|
||||||
exporter, err := prometheus.New()
|
exporter, err := prometheus.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to create prometheus exporter: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := metric.NewMeterProvider(metric.WithReader(exporter))
|
provider := metric.NewMeterProvider(metric.WithReader(exporter))
|
||||||
@@ -213,32 +213,32 @@ func NewDefaultAppMetrics(ctx context.Context) (AppMetrics, error) {
|
|||||||
|
|
||||||
idpMetrics, err := NewIDPMetrics(ctx, meter)
|
idpMetrics, err := NewIDPMetrics(ctx, meter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to initialize IDP metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
middleware, err := NewMetricsMiddleware(ctx, meter)
|
middleware, err := NewMetricsMiddleware(ctx, meter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to initialize HTTP middleware metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
grpcMetrics, err := NewGRPCMetrics(ctx, meter)
|
grpcMetrics, err := NewGRPCMetrics(ctx, meter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to initialize gRPC metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
storeMetrics, err := NewStoreMetrics(ctx, meter)
|
storeMetrics, err := NewStoreMetrics(ctx, meter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to initialize store metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateChannelMetrics, err := NewUpdateChannelMetrics(ctx, meter)
|
updateChannelMetrics, err := NewUpdateChannelMetrics(ctx, meter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to initialize update channel metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
accountManagerMetrics, err := NewAccountManagerMetrics(ctx, meter)
|
accountManagerMetrics, err := NewAccountManagerMetrics(ctx, meter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to initialize account manager metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &defaultAppMetrics{
|
return &defaultAppMetrics{
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ package types
|
|||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
b64 "encoding/base64"
|
b64 "encoding/base64"
|
||||||
"hash/fnv"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/util"
|
"github.com/netbirdio/netbird/management/server/util"
|
||||||
)
|
)
|
||||||
@@ -170,7 +169,7 @@ func GenerateSetupKey(name string, t SetupKeyType, validFor time.Duration, autoG
|
|||||||
encodedHashedKey := b64.StdEncoding.EncodeToString(hashedKey[:])
|
encodedHashedKey := b64.StdEncoding.EncodeToString(hashedKey[:])
|
||||||
|
|
||||||
return &SetupKey{
|
return &SetupKey{
|
||||||
Id: strconv.Itoa(int(Hash(key))),
|
Id: xid.New().String(),
|
||||||
Key: encodedHashedKey,
|
Key: encodedHashedKey,
|
||||||
KeySecret: HiddenKey(key, 4),
|
KeySecret: HiddenKey(key, 4),
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -192,12 +191,3 @@ func GenerateDefaultSetupKey() (*SetupKey, string) {
|
|||||||
return GenerateSetupKey(DefaultSetupKeyName, SetupKeyReusable, DefaultSetupKeyDuration, []string{},
|
return GenerateSetupKey(DefaultSetupKeyName, SetupKeyReusable, DefaultSetupKeyDuration, []string{},
|
||||||
SetupKeyUnlimitedUsage, false, false)
|
SetupKeyUnlimitedUsage, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Hash(s string) uint32 {
|
|
||||||
h := fnv.New32a()
|
|
||||||
_, err := h.Write([]byte(s))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return h.Sum32()
|
|
||||||
}
|
|
||||||
|
|||||||
35
signal/cmd/env.go
Normal file
35
signal/cmd/env.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setFlagsFromEnvVars reads and updates flag values from environment variables with prefix NB_
|
||||||
|
func setFlagsFromEnvVars(cmd *cobra.Command) {
|
||||||
|
flags := cmd.PersistentFlags()
|
||||||
|
flags.VisitAll(func(f *pflag.Flag) {
|
||||||
|
newEnvVar := flagNameToEnvVar(f.Name, "NB_")
|
||||||
|
value, present := os.LookupEnv(newEnvVar)
|
||||||
|
if !present {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := flags.Set(f.Name, value)
|
||||||
|
if err != nil {
|
||||||
|
log.Infof("unable to configure flag %s using variable %s, err: %v", f.Name, newEnvVar, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagNameToEnvVar converts flag name to environment var name adding a prefix,
|
||||||
|
// replacing dashes and making all uppercase (e.g. setup-keys is converted to NB_SETUP_KEYS according to the input prefix)
|
||||||
|
func flagNameToEnvVar(cmdFlag string, prefix string) string {
|
||||||
|
parsed := strings.ReplaceAll(cmdFlag, "-", "_")
|
||||||
|
upper := strings.ToUpper(parsed)
|
||||||
|
return prefix + upper
|
||||||
|
}
|
||||||
@@ -303,4 +303,5 @@ func init() {
|
|||||||
runCmd.Flags().StringVar(&signalLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
runCmd.Flags().StringVar(&signalLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||||
runCmd.Flags().StringVar(&signalCertFile, "cert-file", "", "Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
runCmd.Flags().StringVar(&signalCertFile, "cert-file", "", "Location of your SSL certificate. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
||||||
runCmd.Flags().StringVar(&signalCertKey, "cert-key", "", "Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
runCmd.Flags().StringVar(&signalCertKey, "cert-key", "", "Location of your SSL certificate private key. Can be used when you have an existing certificate and don't want a new certificate be generated automatically. If letsencrypt-domain is specified this property has no effect")
|
||||||
|
setFlagsFromEnvVars(runCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user