From b7c0eba1e541599fa302a9d4013d5f05f1b00c0e Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 27 Nov 2023 17:04:40 +0100 Subject: [PATCH 01/18] add extra settings struct --- management/server/account.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/management/server/account.go b/management/server/account.go index 8f9b1e151f9..bea1886a942 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -158,6 +158,14 @@ type Settings struct { // JWTGroupsClaimName from which we extract groups name to add it to account groups JWTGroupsClaimName string + + // Extra contains additional settings that are not supported in the open-source version + Extra *ExtraSettings +} + +type ExtraSettings struct { + // PeerApprovalEnabled enables or disables the need for peers to be approved by an administrator + PeerApprovalEnabled bool } // Copy copies the Settings struct From a7e55cc5e399f85b7f5c131fb1828781fd3549a8 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 28 Nov 2023 11:44:08 +0100 Subject: [PATCH 02/18] add signatures and frame for peer approval --- go.mod | 2 +- go.sum | 14 +++++++-- management/server/account.go | 35 ++++++++++++++++++++-- management/server/activity/codes.go | 12 ++++++++ management/server/http/accounts_handler.go | 26 +++++++++++----- management/server/http/api/openapi.yml | 17 +++++++++++ management/server/http/api/types.gen.go | 19 ++++++++++++ management/server/http/peers_handler.go | 7 +++++ management/server/peer.go | 24 +++++++++++++-- 9 files changed, 140 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index c6c8221e18e..d4b76653e7f 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88 + github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pion/logging v0.2.2 diff --git a/go.sum b/go.sum index 84b8816e9ba..f316fa0580a 100644 --- a/go.sum +++ b/go.sum @@ -495,8 +495,18 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88 h1:zhe8qseauBuYOS910jpl5sv8Tb+36zxQPXrwYXqll0g= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944 h1:n7o2/NCZzn0+73LGdl/VMh7DOTdWZ98le2woeZ4HlB0= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a h1:6aipBr80s0GPKO9Wl+f5TUOSwebQ91uX2thk9tElyqc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683 h1:jJMO8KL2u3ok5VtGgZtFpuVK0GBEXXIb84idlmqGe68= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a h1:DIe9xdl6RcxeZFu5Pr3OPC8SHM6yadF212W3LJlzfhQ= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a h1:iMEPP7MC3/7DTs/BNMshsBoviG3yWSTRbIzXKdrUwHw= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 h1:PTQ2SSijkoN8Qkctq9oLzEdzCLLv7WoD2dqScmpb15o= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949 h1:xbWM9BU6mwZZLHxEjxIX/V8Hv3HurQt4mReIE4mY4DM= diff --git a/management/server/account.go b/management/server/account.go index bea1886a942..a08416e2c72 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -17,6 +17,7 @@ import ( "github.com/eko/gocache/v3/cache" cacheStore "github.com/eko/gocache/v3/store" + "github.com/netbirdio/management-integrations/integrations" gocache "github.com/patrickmn/go-cache" "github.com/rs/xid" log "github.com/sirupsen/logrus" @@ -159,12 +160,12 @@ type Settings struct { // JWTGroupsClaimName from which we extract groups name to add it to account groups JWTGroupsClaimName string - // Extra contains additional settings that are not supported in the open-source version + // Extra is a dictionary of Account settings Extra *ExtraSettings } type ExtraSettings struct { - // PeerApprovalEnabled enables or disables the need for peers to be approved by an administrator + // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator PeerApprovalEnabled bool } @@ -352,7 +353,20 @@ func (a *Account) GetGroup(groupID string) *Group { // GetPeerNetworkMap returns a group by ID if exists, nil otherwise func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { + peer := a.Peers[peerID] + if peer == nil { + return &NetworkMap{ + Network: a.Network.Copy(), + } + } + validatedPeers := integrations.ValidatePeers([]*Peer{peer}, a) + if len(validatedPeers) == 0 { + return &NetworkMap{ + Network: a.Network.Copy(), + } + } aclPeers, firewallRules := a.getPeerConnectionResources(peerID) + aclPeers = integrations.ValidatePeers(aclPeers, a) // exclude expired peers var peersToConnect []*Peer var expiredPeers []*Peer @@ -879,6 +893,11 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, return nil, err } + err = integrations.ValidateExtraSettings(newSettings.Extra, account, am) + if err != nil { + return nil, err + } + user, err := account.FindUser(userID) if err != nil { return nil, err @@ -905,6 +924,18 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, am.checkAndSchedulePeerLoginExpiration(account) } + // if oldSettings.PeerApprovalEnabled != newSettings.PeerApprovalEnabled { + // event := activity.AccountPeerApprovalEnabled + // if !newSettings.PeerApprovalEnabled { + // event = activity.AccountPeerApprovalDisabled + // } + // am.StoreEvent(userID, accountID, accountID, event, nil) + // + // for _, peer := range account.Peers { + // peer.Status.RequiresApproval = false + // } + // } + updatedAccount := account.UpdateSettings(newSettings) err = am.Store.SaveAccount(account) diff --git a/management/server/activity/codes.go b/management/server/activity/codes.go index 7bad9f627f3..bcd788b6fb9 100644 --- a/management/server/activity/codes.go +++ b/management/server/activity/codes.go @@ -120,6 +120,14 @@ const ( IntegrationUpdated // IntegrationDeleted indicates that the user deleted an integration IntegrationDeleted + // AccountPeerApprovalEnabled indicates that the user enabled peer approval for the account + AccountPeerApprovalEnabled + // AccountPeerApprovalDisabled indicates that the user disabled peer approval for the account + AccountPeerApprovalDisabled + // PeerApproved indicates that the peer has been approved + PeerApproved + // PeerApprovalRevoked indicates that the peer approval has been revoked + PeerApprovalRevoked ) var activityMap = map[Activity]Code{ @@ -178,6 +186,10 @@ var activityMap = map[Activity]Code{ IntegrationCreated: {"Integration created", "integration.create"}, IntegrationUpdated: {"Integration updated", "integration.update"}, IntegrationDeleted: {"Integration deleted", "integration.delete"}, + AccountPeerApprovalEnabled: {"Account peer approval enabled", "account.setting.peer.approval.enable"}, + AccountPeerApprovalDisabled: {"Account peer approval disabled", "account.setting.peer.approval.disable"}, + PeerApproved: {"Peer approved", "peer.approve"}, + PeerApprovalRevoked: {"Peer approval revoked", "peer.approval.revoke"}, } // StringCode returns a string code of the activity diff --git a/management/server/http/accounts_handler.go b/management/server/http/accounts_handler.go index a5d7a9501c4..8c356bb7ad4 100644 --- a/management/server/http/accounts_handler.go +++ b/management/server/http/accounts_handler.go @@ -77,6 +77,10 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request) PeerLoginExpiration: time.Duration(float64(time.Second.Nanoseconds()) * float64(req.Settings.PeerLoginExpiration)), } + if req.Settings.Extra != nil { + settings.Extra = &server.ExtraSettings{PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled} + } + if req.Settings.JwtGroupsEnabled != nil { settings.JWTGroupsEnabled = *req.Settings.JwtGroupsEnabled } @@ -99,14 +103,20 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request) } func toAccountResponse(account *server.Account) *api.Account { + settings := api.AccountSettings{ + PeerLoginExpiration: int(account.Settings.PeerLoginExpiration.Seconds()), + PeerLoginExpirationEnabled: account.Settings.PeerLoginExpirationEnabled, + GroupsPropagationEnabled: &account.Settings.GroupsPropagationEnabled, + JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled, + JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName, + } + + if account.Settings.Extra != nil { + settings.Extra = &api.AccountExtraSettings{PeerApprovalEnabled: &account.Settings.Extra.PeerApprovalEnabled} + } + return &api.Account{ - Id: account.Id, - Settings: api.AccountSettings{ - PeerLoginExpiration: int(account.Settings.PeerLoginExpiration.Seconds()), - PeerLoginExpirationEnabled: account.Settings.PeerLoginExpirationEnabled, - GroupsPropagationEnabled: &account.Settings.GroupsPropagationEnabled, - JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled, - JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName, - }, + Id: account.Id, + Settings: settings, } } diff --git a/management/server/http/api/openapi.yml b/management/server/http/api/openapi.yml index 64e97426a61..6e98f4c7e9c 100644 --- a/management/server/http/api/openapi.yml +++ b/management/server/http/api/openapi.yml @@ -66,9 +66,18 @@ components: description: Name of the claim from which we extract groups names to add it to account groups. type: string example: "roles" + extra: + $ref: '#/components/schemas/AccountExtraSettings' required: - peer_login_expiration_enabled - peer_login_expiration + AccountExtraSettings: + type: object + properties: + peer_approval_enabled: + description: Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. + type: boolean + example: true AccountRequest: type: object properties: @@ -213,6 +222,10 @@ components: login_expiration_enabled: type: boolean example: false + approval_required: + description: (Cloud only) Indicates whether peer needs approval + type: boolean + example: true required: - name - ssh_enabled @@ -281,6 +294,10 @@ components: type: string format: date-time example: 2023-05-05T09:00:35.477782Z + approval_required: + description: (Cloud only) Indicates whether peer needs approval + type: boolean + example: true required: - ip - connected diff --git a/management/server/http/api/types.gen.go b/management/server/http/api/types.gen.go index ea70b7f3a84..5298e887bf0 100644 --- a/management/server/http/api/types.gen.go +++ b/management/server/http/api/types.gen.go @@ -142,6 +142,12 @@ type Account struct { Settings AccountSettings `json:"settings"` } +// AccountExtraSettings defines model for AccountExtraSettings. +type AccountExtraSettings struct { + // PeerApprovalEnabled Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. + PeerApprovalEnabled *bool `json:"peer_approval_enabled,omitempty"` +} + // AccountRequest defines model for AccountRequest. type AccountRequest struct { Settings AccountSettings `json:"settings"` @@ -149,6 +155,8 @@ type AccountRequest struct { // AccountSettings defines model for AccountSettings. type AccountSettings struct { + Extra *AccountExtraSettings `json:"extra,omitempty"` + // GroupsPropagationEnabled Allows propagate the new user auto groups to peers that belongs to the user GroupsPropagationEnabled *bool `json:"groups_propagation_enabled,omitempty"` @@ -323,6 +331,9 @@ type Peer struct { // AccessiblePeers List of accessible peers AccessiblePeers []AccessiblePeer `json:"accessible_peers"` + // ApprovalRequired (Cloud only) Indicates whether peer needs approval + ApprovalRequired *bool `json:"approval_required,omitempty"` + // Connected Peer to Management connection status Connected bool `json:"connected"` @@ -374,6 +385,9 @@ type Peer struct { // PeerBase defines model for PeerBase. type PeerBase struct { + // ApprovalRequired (Cloud only) Indicates whether peer needs approval + ApprovalRequired *bool `json:"approval_required,omitempty"` + // Connected Peer to Management connection status Connected bool `json:"connected"` @@ -428,6 +442,9 @@ type PeerBatch struct { // AccessiblePeersCount Number of accessible peers AccessiblePeersCount int `json:"accessible_peers_count"` + // ApprovalRequired (Cloud only) Indicates whether peer needs approval + ApprovalRequired *bool `json:"approval_required,omitempty"` + // Connected Peer to Management connection status Connected bool `json:"connected"` @@ -488,6 +505,8 @@ type PeerMinimum struct { // PeerRequest defines model for PeerRequest. type PeerRequest struct { + // ApprovalRequired (Cloud only) Indicates whether peer needs approval + ApprovalRequired *bool `json:"approval_required,omitempty"` LoginExpirationEnabled bool `json:"login_expiration_enabled"` Name string `json:"name"` SshEnabled bool `json:"ssh_enabled"` diff --git a/management/server/http/peers_handler.go b/management/server/http/peers_handler.go index 3d0d735ecea..c143a8076d3 100644 --- a/management/server/http/peers_handler.go +++ b/management/server/http/peers_handler.go @@ -81,6 +81,11 @@ func (h *PeersHandler) updatePeer(account *server.Account, user *server.User, pe update := &server.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name, LoginExpirationEnabled: req.LoginExpirationEnabled} + + if req.ApprovalRequired != nil { + update.Status = &server.PeerStatus{RequiresApproval: *req.ApprovalRequired} + } + peer, err := h.accountManager.UpdatePeer(account.Id, user.Id, update) if err != nil { util.WriteError(err, w) @@ -248,6 +253,7 @@ func toSinglePeerResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dnsD LastLogin: peer.LastLogin, LoginExpired: peer.Status.LoginExpired, AccessiblePeers: accessiblePeer, + Approved: &peer.Status.Approved, } } @@ -270,6 +276,7 @@ func toPeerListItemResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dn LastLogin: peer.LastLogin, LoginExpired: peer.Status.LoginExpired, AccessiblePeersCount: accessiblePeersCount, + Approved: peer.Status.Approved, } } diff --git a/management/server/peer.go b/management/server/peer.go index 27912f1f4d9..6268ae7944b 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/netbirdio/management-integrations/integrations" "github.com/rs/xid" "github.com/netbirdio/netbird/management/server/activity" @@ -46,6 +47,8 @@ type PeerStatus struct { Connected bool // LoginExpired LoginExpired bool + // RequiresApproval indicates whether peer requires approval or not + RequiresApproval bool } // PeerSync used as a data object between the gRPC API and AccountManager on Sync request. @@ -192,9 +195,10 @@ func (p *Peer) EventMeta(dnsDomain string) map[string]any { // Copy PeerStatus func (p *PeerStatus) Copy() *PeerStatus { return &PeerStatus{ - LastSeen: p.LastSeen, - Connected: p.Connected, - LoginExpired: p.LoginExpired, + LastSeen: p.LastSeen, + Connected: p.Connected, + LoginExpired: p.LoginExpired, + RequiresApproval: p.RequiresApproval, } } @@ -304,6 +308,11 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Pe return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID) } + update, err = integrations.ValidatePeersUpdateRequest(update, peer, am) + if err != nil { + return nil, err + } + if peer.SSHEnabled != update.SSHEnabled { peer.SSHEnabled = update.SSHEnabled event := activity.PeerSSHEnabled @@ -562,6 +571,10 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (* Ephemeral: ephemeral, } + if account.Settings.Extra.PeerApprovalEnabled { + newPeer.Status.RequiresApproval = true + } + // add peer to 'All' group group, err := account.GetGroupAll() if err != nil { @@ -632,6 +645,11 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*Peer, *NetworkMap, er return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered") } + validatedPeers := integrations.ValidatePeers([]*Peer{peer}, account) + if len(validatedPeers) == 0 { + return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed") + } + err = checkIfPeerOwnerIsBlocked(peer, account) if err != nil { return nil, nil, err From a729c83b0659827159246a5755da6f16c076d12c Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 28 Nov 2023 13:45:26 +0100 Subject: [PATCH 03/18] extract peer into seperate package --- go.mod | 2 +- go.sum | 2 + management/server/account.go | 88 +++--- management/server/account_test.go | 276 +++++++++++++++---- management/server/dns.go | 3 +- management/server/dns_test.go | 9 +- management/server/ephemeral.go | 5 +- management/server/ephemeral_test.go | 6 +- management/server/file_store.go | 5 +- management/server/file_store_test.go | 23 +- management/server/grpcserver.go | 15 +- management/server/http/peers_handler_test.go | 3 +- management/server/nameserver_test.go | 9 +- management/server/network.go | 5 +- management/server/peer.go | 218 ++------------- management/server/peer/peer.go | 181 ++++++++++++ management/server/peer_test.go | 36 +-- management/server/policy.go | 15 +- management/server/policy_test.go | 6 +- management/server/route_test.go | 21 +- management/server/sqlite_store.go | 22 +- management/server/sqlite_store_test.go | 30 +- management/server/store.go | 3 +- management/server/user.go | 3 +- 24 files changed, 587 insertions(+), 399 deletions(-) create mode 100644 management/server/peer/peer.go diff --git a/go.mod b/go.mod index d4b76653e7f..44d7cd6ec6f 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 + github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pion/logging v0.2.2 diff --git a/go.sum b/go.sum index f316fa0580a..4038f9b5fdd 100644 --- a/go.sum +++ b/go.sum @@ -507,6 +507,8 @@ github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411- github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 h1:PTQ2SSijkoN8Qkctq9oLzEdzCLLv7WoD2dqScmpb15o= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262 h1:JVImKBfZC2tC88GcJS0Hi6sdFL+FkhCcmbpU8lRAWss= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949 h1:xbWM9BU6mwZZLHxEjxIX/V8Hv3HurQt4mReIE4mY4DM= diff --git a/management/server/account.go b/management/server/account.go index a08416e2c72..1563570fa26 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -27,6 +27,7 @@ import ( "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/idp" "github.com/netbirdio/netbird/management/server/jwtclaims" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/route" ) @@ -68,13 +69,13 @@ type AccountManager interface { MarkPATUsed(tokenID string) error GetUser(claims jwtclaims.AuthorizationClaims) (*User, error) ListUsers(accountID string) ([]*User, error) - GetPeers(accountID, userID string) ([]*Peer, error) + GetPeers(accountID, userID string) ([]*nbpeer.Peer, error) MarkPeerConnected(peerKey string, connected bool) error DeletePeer(accountID, peerID, userID string) error - UpdatePeer(accountID, userID string, peer *Peer) (*Peer, error) + UpdatePeer(accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) GetNetworkMap(peerID string) (*NetworkMap, error) GetPeerNetwork(peerID string) (*Network, error) - AddPeer(setupKey, userID string, peer *Peer) (*Peer, *NetworkMap, error) + AddPeer(setupKey, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, *NetworkMap, error) CreatePAT(accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*PersonalAccessTokenGenerated, error) DeletePAT(accountID string, initiatorUserID string, targetUserID string, tokenID string) error GetPAT(accountID string, initiatorUserID string, targetUserID string, tokenID string) (*PersonalAccessToken, error) @@ -106,10 +107,10 @@ type AccountManager interface { GetEvents(accountID, userID string) ([]*activity.Event, error) GetDNSSettings(accountID string, userID string) (*DNSSettings, error) SaveDNSSettings(accountID string, userID string, dnsSettingsToSave *DNSSettings) error - GetPeer(accountID, peerID, userID string) (*Peer, error) + GetPeer(accountID, peerID, userID string) (*nbpeer.Peer, error) UpdateAccountSettings(accountID, userID string, newSettings *Settings) (*Account, error) - LoginPeer(login PeerLogin) (*Peer, *NetworkMap, error) // used by peer gRPC API - SyncPeer(sync PeerSync) (*Peer, *NetworkMap, error) // used by peer gRPC API + LoginPeer(login PeerLogin) (*nbpeer.Peer, *NetworkMap, error) // used by peer gRPC API + SyncPeer(sync PeerSync) (*nbpeer.Peer, *NetworkMap, error) // used by peer gRPC API GetAllConnectedPeers() (map[string]struct{}, error) GetExternalCacheManager() ExternalCacheManager } @@ -164,20 +165,31 @@ type Settings struct { Extra *ExtraSettings } -type ExtraSettings struct { - // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator - PeerApprovalEnabled bool -} - // Copy copies the Settings struct func (s *Settings) Copy() *Settings { - return &Settings{ + settings := &Settings{ PeerLoginExpirationEnabled: s.PeerLoginExpirationEnabled, PeerLoginExpiration: s.PeerLoginExpiration, JWTGroupsEnabled: s.JWTGroupsEnabled, JWTGroupsClaimName: s.JWTGroupsClaimName, GroupsPropagationEnabled: s.GroupsPropagationEnabled, } + if s.Extra != nil { + settings.Extra = s.Extra.Copy() + } + return settings +} + +type ExtraSettings struct { + // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator + PeerApprovalEnabled bool +} + +// Copy copies the ExtraSettings struct +func (e *ExtraSettings) Copy() *ExtraSettings { + return &ExtraSettings{ + PeerApprovalEnabled: e.PeerApprovalEnabled, + } } // Account represents a unique account of the system @@ -193,8 +205,8 @@ type Account struct { SetupKeys map[string]*SetupKey `gorm:"-"` SetupKeysG []SetupKey `json:"-" gorm:"foreignKey:AccountID;references:id"` Network *Network `gorm:"embedded;embeddedPrefix:network_"` - Peers map[string]*Peer `gorm:"-"` - PeersG []Peer `json:"-" gorm:"foreignKey:AccountID;references:id"` + Peers map[string]*nbpeer.Peer `gorm:"-"` + PeersG []nbpeer.Peer `json:"-" gorm:"foreignKey:AccountID;references:id"` Users map[string]*User `gorm:"-"` UsersG []User `json:"-" gorm:"foreignKey:AccountID;references:id"` Groups map[string]*Group `gorm:"-"` @@ -229,7 +241,7 @@ type UserInfo struct { // getRoutesToSync returns the enabled routes for the peer ID and the routes // from the ACL peers that have distribution groups associated with the peer ID. // Please mind, that the returned route.Route objects will contain Peer.Key instead of Peer.ID. -func (a *Account) getRoutesToSync(peerID string, aclPeers []*Peer) []*route.Route { +func (a *Account) getRoutesToSync(peerID string, aclPeers []*nbpeer.Peer) []*route.Route { routes, peerDisabledRoutes := a.getRoutingPeerRoutes(peerID) peerRoutesMembership := make(lookupMap) for _, r := range append(routes, peerDisabledRoutes...) { @@ -359,7 +371,7 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { Network: a.Network.Copy(), } } - validatedPeers := integrations.ValidatePeers([]*Peer{peer}, a) + validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}, a) if len(validatedPeers) == 0 { return &NetworkMap{ Network: a.Network.Copy(), @@ -368,8 +380,8 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { aclPeers, firewallRules := a.getPeerConnectionResources(peerID) aclPeers = integrations.ValidatePeers(aclPeers, a) // exclude expired peers - var peersToConnect []*Peer - var expiredPeers []*Peer + var peersToConnect []*nbpeer.Peer + var expiredPeers []*nbpeer.Peer for _, p := range aclPeers { expired, _ := p.LoginExpired(a.Settings.PeerLoginExpiration) if a.Settings.PeerLoginExpirationEnabled && expired { @@ -407,8 +419,8 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { } // GetExpiredPeers returns peers that have been expired -func (a *Account) GetExpiredPeers() []*Peer { - var peers []*Peer +func (a *Account) GetExpiredPeers() []*nbpeer.Peer { + var peers []*nbpeer.Peer for _, peer := range a.GetPeersWithExpiration() { expired, _ := peer.LoginExpired(a.Settings.PeerLoginExpiration) if expired { @@ -447,8 +459,8 @@ func (a *Account) GetNextPeerExpiration() (time.Duration, bool) { } // GetPeersWithExpiration returns a list of peers that have Peer.LoginExpirationEnabled set to true and that were added by a user -func (a *Account) GetPeersWithExpiration() []*Peer { - peers := make([]*Peer, 0) +func (a *Account) GetPeersWithExpiration() []*nbpeer.Peer { + peers := make([]*nbpeer.Peer, 0) for _, peer := range a.Peers { if peer.LoginExpirationEnabled && peer.AddedWithSSOLogin() { peers = append(peers, peer) @@ -458,8 +470,8 @@ func (a *Account) GetPeersWithExpiration() []*Peer { } // GetPeers returns a list of all Account peers -func (a *Account) GetPeers() []*Peer { - var peers []*Peer +func (a *Account) GetPeers() []*nbpeer.Peer { + var peers []*nbpeer.Peer for _, peer := range a.Peers { peers = append(peers, peer) } @@ -473,7 +485,7 @@ func (a *Account) UpdateSettings(update *Settings) *Account { } // UpdatePeer saves new or replaces existing peer -func (a *Account) UpdatePeer(update *Peer) { +func (a *Account) UpdatePeer(update *nbpeer.Peer) { a.Peers[update.ID] = update } @@ -502,7 +514,7 @@ func (a *Account) DeletePeer(peerID string) { // FindPeerByPubKey looks for a Peer by provided WireGuard public key in the Account or returns error if it wasn't found. // It will return an object copy of the peer. -func (a *Account) FindPeerByPubKey(peerPubKey string) (*Peer, error) { +func (a *Account) FindPeerByPubKey(peerPubKey string) (*nbpeer.Peer, error) { for _, peer := range a.Peers { if peer.Key == peerPubKey { return peer.Copy(), nil @@ -513,8 +525,8 @@ func (a *Account) FindPeerByPubKey(peerPubKey string) (*Peer, error) { } // FindUserPeers returns a list of peers that user owns (created) -func (a *Account) FindUserPeers(userID string) ([]*Peer, error) { - peers := make([]*Peer, 0) +func (a *Account) FindUserPeers(userID string) ([]*nbpeer.Peer, error) { + peers := make([]*nbpeer.Peer, 0) for _, peer := range a.Peers { if peer.UserID == userID { peers = append(peers, peer) @@ -606,7 +618,7 @@ func (a *Account) getPeerDNSLabels() lookupMap { } func (a *Account) Copy() *Account { - peers := map[string]*Peer{} + peers := map[string]*nbpeer.Peer{} for id, peer := range a.Peers { peers[id] = peer.Copy() } @@ -683,7 +695,7 @@ func (a *Account) GetGroupAll() (*Group, error) { } // GetPeer looks up a Peer by ID -func (a *Account) GetPeer(peerID string) *Peer { +func (a *Account) GetPeer(peerID string) *nbpeer.Peer { return a.Peers[peerID] } @@ -893,7 +905,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, return nil, err } - err = integrations.ValidateExtraSettings(newSettings.Extra, account, am) + err = integrations.ValidateExtraSettings(newSettings.Extra, account, userID, am) if err != nil { return nil, err } @@ -924,18 +936,6 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, am.checkAndSchedulePeerLoginExpiration(account) } - // if oldSettings.PeerApprovalEnabled != newSettings.PeerApprovalEnabled { - // event := activity.AccountPeerApprovalEnabled - // if !newSettings.PeerApprovalEnabled { - // event = activity.AccountPeerApprovalDisabled - // } - // am.StoreEvent(userID, accountID, accountID, event, nil) - // - // for _, peer := range account.Peers { - // peer.Status.RequiresApproval = false - // } - // } - updatedAccount := account.UpdateSettings(newSettings) err = am.Store.SaveAccount(account) @@ -1683,7 +1683,7 @@ func newAccountWithId(accountID, userID, domain string) *Account { log.Debugf("creating new account") network := NewNetwork() - peers := make(map[string]*Peer) + peers := make(map[string]*nbpeer.Peer) users := make(map[string]*User) routes := make(map[string]*route.Route) setupKeys := map[string]*SetupKey{} diff --git a/management/server/account_test.go b/management/server/account_test.go index ad0ccfbcea7..9be9d8257c7 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -15,6 +15,7 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/route" "github.com/stretchr/testify/assert" @@ -26,10 +27,10 @@ import ( func verifyCanAddPeerToAccount(t *testing.T, manager AccountManager, account *Account, userID string) { t.Helper() - peer := &Peer{ + peer := &nbpeer.Peer{ Key: "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8=", Name: "test-host@netbird.io", - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host@netbird.io", GoOS: "linux", Kernel: "Linux", @@ -110,13 +111,14 @@ func verifyNewAccountHasDefaultFields(t *testing.T, account *Account, createdBy func TestAccount_GetPeerNetworkMap(t *testing.T) { peerID1 := "peer-1" peerID2 := "peer-2" + // peerID3 := "peer-3" tt := []struct { name string accountSettings Settings peerID string expectedPeers []string expectedOfflinePeers []string - peers map[string]*Peer + peers map[string]*nbpeer.Peer }{ { name: "Should return ALL peers when global peer login expiration disabled", @@ -124,14 +126,14 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) { peerID: peerID1, expectedPeers: []string{peerID2}, expectedOfflinePeers: []string{}, - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { ID: peerID1, Key: "peer-1-key", IP: net.IP{100, 64, 0, 1}, Name: peerID1, DNSLabel: peerID1, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: false, LoginExpired: true, @@ -145,7 +147,7 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) { IP: net.IP{100, 64, 0, 1}, Name: peerID2, DNSLabel: peerID2, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: false, LoginExpired: false, @@ -162,14 +164,14 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) { peerID: peerID1, expectedPeers: []string{}, expectedOfflinePeers: []string{peerID2}, - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { ID: peerID1, Key: "peer-1-key", IP: net.IP{100, 64, 0, 1}, Name: peerID1, DNSLabel: peerID1, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: false, LoginExpired: true, @@ -184,7 +186,7 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) { IP: net.IP{100, 64, 0, 1}, Name: peerID2, DNSLabel: peerID2, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: false, LoginExpired: true, @@ -195,6 +197,159 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) { }, }, }, + // { + // name: "Should return only peers that are approved when peer approval is enabled", + // accountSettings: Settings{PeerApprovalEnabled: true}, + // peerID: peerID1, + // expectedPeers: []string{peerID3}, + // expectedOfflinePeers: []string{}, + // peers: map[string]*Peer{ + // "peer-1": { + // ID: peerID1, + // Key: "peer-1-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID1, + // DNSLabel: peerID1, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: true, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // "peer-2": { + // ID: peerID2, + // Key: "peer-2-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID2, + // DNSLabel: peerID2, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: false, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // "peer-3": { + // ID: peerID3, + // Key: "peer-3-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID3, + // DNSLabel: peerID3, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: true, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // }, + // }, + // { + // name: "Should return all peers when peer approval is disabled", + // accountSettings: Settings{PeerApprovalEnabled: false}, + // peerID: peerID1, + // expectedPeers: []string{peerID2, peerID3}, + // expectedOfflinePeers: []string{}, + // peers: map[string]*Peer{ + // "peer-1": { + // ID: peerID1, + // Key: "peer-1-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID1, + // DNSLabel: peerID1, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: true, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // "peer-2": { + // ID: peerID2, + // Key: "peer-2-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID2, + // DNSLabel: peerID2, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: false, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // "peer-3": { + // ID: peerID3, + // Key: "peer-3-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID3, + // DNSLabel: peerID3, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: true, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // }, + // }, + // { + // name: "Should return no peers when peer approval is enabled and the requesting peer is not approved", + // accountSettings: Settings{PeerApprovalEnabled: true}, + // peerID: peerID1, + // expectedPeers: []string{}, + // expectedOfflinePeers: []string{}, + // peers: map[string]*Peer{ + // "peer-1": { + // ID: peerID1, + // Key: "peer-1-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID1, + // DNSLabel: peerID1, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: false, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // "peer-2": { + // ID: peerID2, + // Key: "peer-2-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID2, + // DNSLabel: peerID2, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: true, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // "peer-3": { + // ID: peerID3, + // Key: "peer-3-key", + // IP: net.IP{100, 64, 0, 1}, + // Name: peerID3, + // DNSLabel: peerID3, + // Status: &PeerStatus{ + // LastSeen: time.Now().UTC(), + // Connected: false, + // Approved: true, + // }, + // UserID: userID, + // LastLogin: time.Now().UTC().Add(-time.Hour * 24 * 30 * 30), + // }, + // }, + // }, } netIP := net.IP{100, 64, 0, 0} @@ -209,6 +364,7 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) { for _, testCase := range tt { account := newAccountWithId("account-1", userID, "netbird.io") + account.UpdateSettings(&testCase.accountSettings) account.Network = network account.Peers = testCase.peers for _, peer := range account.Peers { @@ -780,9 +936,9 @@ func TestAccountManager_AddPeer(t *testing.T) { expectedPeerKey := key.PublicKey().String() expectedSetupKey := setupKey.Key - peer, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: expectedPeerKey, - Meta: PeerSystemMeta{Hostname: expectedPeerKey}, + Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -848,9 +1004,9 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) { expectedPeerKey := key.PublicKey().String() expectedUserID := userID - peer, _, err := manager.AddPeer("", userID, &Peer{ + peer, _, err := manager.AddPeer("", userID, &nbpeer.Peer{ Key: expectedPeerKey, - Meta: PeerSystemMeta{Hostname: expectedPeerKey}, + Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v, account users: %v", err, account.CreatedBy) @@ -915,7 +1071,7 @@ func TestAccountManager_NetworkUpdates(t *testing.T) { return } - getPeer := func() *Peer { + getPeer := func() *nbpeer.Peer { key, err := wgtypes.GeneratePrivateKey() if err != nil { t.Fatal(err) @@ -923,9 +1079,9 @@ func TestAccountManager_NetworkUpdates(t *testing.T) { } expectedPeerKey := key.PublicKey().String() - peer, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: expectedPeerKey, - Meta: PeerSystemMeta{Hostname: expectedPeerKey}, + Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey}, }) if err != nil { t.Fatalf("expecting peer1 to be added, got failure %v", err) @@ -1097,9 +1253,9 @@ func TestAccountManager_DeletePeer(t *testing.T) { peerKey := key.PublicKey().String() - peer, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey, - Meta: PeerSystemMeta{Hostname: peerKey}, + Meta: nbpeer.PeerSystemMeta{Hostname: peerKey}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -1238,8 +1394,8 @@ func TestAccount_GetRoutesToSync(t *testing.T) { t.Fatal(err) } account := &Account{ - Peers: map[string]*Peer{ - "peer-1": {Key: "peer-1", Meta: PeerSystemMeta{GoOS: "linux"}}, "peer-2": {Key: "peer-2", Meta: PeerSystemMeta{GoOS: "linux"}}, "peer-3": {Key: "peer-1", Meta: PeerSystemMeta{GoOS: "linux"}}, + Peers: map[string]*nbpeer.Peer{ + "peer-1": {Key: "peer-1", Meta: nbpeer.PeerSystemMeta{GoOS: "linux"}}, "peer-2": {Key: "peer-2", Meta: nbpeer.PeerSystemMeta{GoOS: "linux"}}, "peer-3": {Key: "peer-1", Meta: nbpeer.PeerSystemMeta{GoOS: "linux"}}, }, Groups: map[string]*Group{"group1": {ID: "group1", Peers: []string{"peer-1", "peer-2"}}}, Routes: map[string]*route.Route{ @@ -1282,7 +1438,7 @@ func TestAccount_GetRoutesToSync(t *testing.T) { }, } - routes := account.getRoutesToSync("peer-2", []*Peer{{Key: "peer-1"}, {Key: "peer-3"}}) + routes := account.getRoutesToSync("peer-2", []*nbpeer.Peer{{Key: "peer-1"}, {Key: "peer-3"}}) assert.Len(t, routes, 2) routeIDs := make(map[string]struct{}, 2) @@ -1292,7 +1448,7 @@ func TestAccount_GetRoutesToSync(t *testing.T) { assert.Contains(t, routeIDs, "route-2") assert.Contains(t, routeIDs, "route-3") - emptyRoutes := account.getRoutesToSync("peer-3", []*Peer{{Key: "peer-1"}, {Key: "peer-2"}}) + emptyRoutes := account.getRoutesToSync("peer-3", []*nbpeer.Peer{{Key: "peer-1"}, {Key: "peer-2"}}) assert.Len(t, emptyRoutes, 0) } @@ -1313,10 +1469,10 @@ func TestAccount_Copy(t *testing.T) { Network: &Network{ Identifier: "net1", }, - Peers: map[string]*Peer{ + Peers: map[string]*nbpeer.Peer{ "peer1": { Key: "key1", - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now(), Connected: true, LoginExpired: false, @@ -1443,9 +1599,9 @@ func TestDefaultAccountManager_UpdatePeer_PeerLoginExpiration(t *testing.T) { key, err := wgtypes.GenerateKey() require.NoError(t, err, "unable to generate WireGuard key") - peer, _, err := manager.AddPeer("", userID, &Peer{ + peer, _, err := manager.AddPeer("", userID, &nbpeer.Peer{ Key: key.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"}, LoginExpirationEnabled: true, }) require.NoError(t, err, "unable to add peer") @@ -1492,9 +1648,9 @@ func TestDefaultAccountManager_MarkPeerConnected_PeerLoginExpiration(t *testing. key, err := wgtypes.GenerateKey() require.NoError(t, err, "unable to generate WireGuard key") - _, _, err = manager.AddPeer("", userID, &Peer{ + _, _, err = manager.AddPeer("", userID, &nbpeer.Peer{ Key: key.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"}, LoginExpirationEnabled: true, }) require.NoError(t, err, "unable to add peer") @@ -1533,9 +1689,9 @@ func TestDefaultAccountManager_UpdateAccountSettings_PeerLoginExpiration(t *test key, err := wgtypes.GenerateKey() require.NoError(t, err, "unable to generate WireGuard key") - _, _, err = manager.AddPeer("", userID, &Peer{ + _, _, err = manager.AddPeer("", userID, &nbpeer.Peer{ Key: key.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"}, LoginExpirationEnabled: true, }) require.NoError(t, err, "unable to add peer") @@ -1614,13 +1770,13 @@ func TestDefaultAccountManager_UpdateAccountSettings(t *testing.T) { func TestAccount_GetExpiredPeers(t *testing.T) { type test struct { name string - peers map[string]*Peer + peers map[string]*nbpeer.Peer expectedPeers map[string]struct{} } testCases := []test{ { name: "Peers with login expiration disabled, no expired peers", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { LoginExpirationEnabled: false, }, @@ -1632,11 +1788,11 @@ func TestAccount_GetExpiredPeers(t *testing.T) { }, { name: "Two peers expired", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { ID: "peer-1", LoginExpirationEnabled: true, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: true, LoginExpired: false, @@ -1647,7 +1803,7 @@ func TestAccount_GetExpiredPeers(t *testing.T) { "peer-2": { ID: "peer-2", LoginExpirationEnabled: true, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: true, LoginExpired: false, @@ -1659,7 +1815,7 @@ func TestAccount_GetExpiredPeers(t *testing.T) { "peer-3": { ID: "peer-3", LoginExpirationEnabled: true, - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ LastSeen: time.Now().UTC(), Connected: true, LoginExpired: false, @@ -1699,19 +1855,19 @@ func TestAccount_GetExpiredPeers(t *testing.T) { func TestAccount_GetPeersWithExpiration(t *testing.T) { type test struct { name string - peers map[string]*Peer + peers map[string]*nbpeer.Peer expectedPeers map[string]struct{} } testCases := []test{ { name: "No account peers, no peers with expiration", - peers: map[string]*Peer{}, + peers: map[string]*nbpeer.Peer{}, expectedPeers: map[string]struct{}{}, }, { name: "Peers with login expiration disabled, no peers with expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { LoginExpirationEnabled: false, UserID: userID, @@ -1725,7 +1881,7 @@ func TestAccount_GetPeersWithExpiration(t *testing.T) { }, { name: "Peers with login expiration enabled, return peers with expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { ID: "peer-1", LoginExpirationEnabled: true, @@ -1768,7 +1924,7 @@ func TestAccount_GetPeersWithExpiration(t *testing.T) { func TestAccount_GetNextPeerExpiration(t *testing.T) { type test struct { name string - peers map[string]*Peer + peers map[string]*nbpeer.Peer expiration time.Duration expirationEnabled bool expectedNextRun bool @@ -1779,7 +1935,7 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { testCases := []test{ { name: "No peers, no expiration", - peers: map[string]*Peer{}, + peers: map[string]*nbpeer.Peer{}, expiration: time.Second, expirationEnabled: false, expectedNextRun: false, @@ -1787,16 +1943,16 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { }, { name: "No connected peers, no expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: false, }, LoginExpirationEnabled: true, UserID: userID, }, "peer-2": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, }, LoginExpirationEnabled: false, @@ -1810,16 +1966,16 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { }, { name: "Connected peers with disabled expiration, no expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, }, LoginExpirationEnabled: false, UserID: userID, }, "peer-2": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, }, LoginExpirationEnabled: false, @@ -1833,9 +1989,9 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { }, { name: "Expired peers, no expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, LoginExpired: true, }, @@ -1843,7 +1999,7 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { UserID: userID, }, "peer-2": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, LoginExpired: true, }, @@ -1858,9 +2014,9 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { }, { name: "To be expired peer, return expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, LoginExpired: false, }, @@ -1869,7 +2025,7 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { UserID: userID, }, "peer-2": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, LoginExpired: true, }, @@ -1884,9 +2040,9 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { }, { name: "Peers added with setup keys, no expiration", - peers: map[string]*Peer{ + peers: map[string]*nbpeer.Peer{ "peer-1": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, LoginExpired: false, }, @@ -1894,7 +2050,7 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { SetupKey: "key", }, "peer-2": { - Status: &PeerStatus{ + Status: &nbpeer.PeerStatus{ Connected: true, LoginExpired: false, }, @@ -1929,7 +2085,7 @@ func TestAccount_GetNextPeerExpiration(t *testing.T) { func TestAccount_SetJWTGroups(t *testing.T) { // create a new account account := &Account{ - Peers: map[string]*Peer{ + Peers: map[string]*nbpeer.Peer{ "peer1": {ID: "peer1", Key: "key1", UserID: "user1"}, "peer2": {ID: "peer2", Key: "key2", UserID: "user1"}, "peer3": {ID: "peer3", Key: "key3", UserID: "user1"}, @@ -1977,7 +2133,7 @@ func TestAccount_SetJWTGroups(t *testing.T) { func TestAccount_UserGroupsAddToPeers(t *testing.T) { account := &Account{ - Peers: map[string]*Peer{ + Peers: map[string]*nbpeer.Peer{ "peer1": {ID: "peer1", Key: "key1", UserID: "user1"}, "peer2": {ID: "peer2", Key: "key2", UserID: "user1"}, "peer3": {ID: "peer3", Key: "key3", UserID: "user1"}, @@ -2013,7 +2169,7 @@ func TestAccount_UserGroupsAddToPeers(t *testing.T) { func TestAccount_UserGroupsRemoveFromPeers(t *testing.T) { account := &Account{ - Peers: map[string]*Peer{ + Peers: map[string]*nbpeer.Peer{ "peer1": {ID: "peer1", Key: "key1", UserID: "user1"}, "peer2": {ID: "peer2", Key: "key2", UserID: "user1"}, "peer3": {ID: "peer3", Key: "key3", UserID: "user1"}, diff --git a/management/server/dns.go b/management/server/dns.go index 4f7f95aaf49..236ba1f57b1 100644 --- a/management/server/dns.go +++ b/management/server/dns.go @@ -10,6 +10,7 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/proto" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" ) @@ -200,7 +201,7 @@ func getPeerNSGroups(account *Account, peerID string) []*nbdns.NameServerGroup { } // peerIsNameserver returns true if the peer is a nameserver for a nsGroup -func peerIsNameserver(peer *Peer, nsGroup *nbdns.NameServerGroup) bool { +func peerIsNameserver(peer *nbpeer.Peer, nsGroup *nbdns.NameServerGroup) bool { for _, ns := range nsGroup.NameServers { if peer.IP.Equal(ns.IP.AsSlice()) { return true diff --git a/management/server/dns_test.go b/management/server/dns_test.go index 62408e4b37d..bff0c987845 100644 --- a/management/server/dns_test.go +++ b/management/server/dns_test.go @@ -8,6 +8,7 @@ import ( "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" ) @@ -208,10 +209,10 @@ func createDNSStore(t *testing.T) (Store, error) { func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) { t.Helper() - peer1 := &Peer{ + peer1 := &nbpeer.Peer{ Key: dnsPeer1Key, Name: "test-host1@netbird.io", - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host1@netbird.io", GoOS: "linux", Kernel: "Linux", @@ -223,10 +224,10 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, erro }, DNSLabel: dnsPeer1Key, } - peer2 := &Peer{ + peer2 := &nbpeer.Peer{ Key: dnsPeer2Key, Name: "test-host2@netbird.io", - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host2@netbird.io", GoOS: "linux", Kernel: "Linux", diff --git a/management/server/ephemeral.go b/management/server/ephemeral.go index 0e76e58acc9..9d70a05d148 100644 --- a/management/server/ephemeral.go +++ b/management/server/ephemeral.go @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" ) const ( @@ -72,7 +73,7 @@ func (e *EphemeralManager) Stop() { // OnPeerConnected remove the peer from the linked list of ephemeral peers. Because it has been called when the peer // is active the manager will not delete it while it is active. -func (e *EphemeralManager) OnPeerConnected(peer *Peer) { +func (e *EphemeralManager) OnPeerConnected(peer *nbpeer.Peer) { if !peer.Ephemeral { return } @@ -93,7 +94,7 @@ func (e *EphemeralManager) OnPeerConnected(peer *Peer) { // OnPeerDisconnected add the peer to the linked list of ephemeral peers. Because of the peer // is inactive it will be deleted after the ephemeralLifeTime period. -func (e *EphemeralManager) OnPeerDisconnected(peer *Peer) { +func (e *EphemeralManager) OnPeerDisconnected(peer *nbpeer.Peer) { if !peer.Ephemeral { return } diff --git a/management/server/ephemeral_test.go b/management/server/ephemeral_test.go index d271e5fcafe..3e36335e3a5 100644 --- a/management/server/ephemeral_test.go +++ b/management/server/ephemeral_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" "time" + + nbpeer "github.com/netbirdio/netbird/management/server/peer" ) type MockStore struct { @@ -124,7 +126,7 @@ func seedPeers(store *MockStore, numberOfPeers int, numberOfEphemeralPeers int) for i := 0; i < numberOfPeers; i++ { peerId := fmt.Sprintf("peer_%d", i) - p := &Peer{ + p := &nbpeer.Peer{ ID: peerId, Ephemeral: false, } @@ -133,7 +135,7 @@ func seedPeers(store *MockStore, numberOfPeers int, numberOfEphemeralPeers int) for i := 0; i < numberOfEphemeralPeers; i++ { peerId := fmt.Sprintf("ephemeral_peer_%d", i) - p := &Peer{ + p := &nbpeer.Peer{ ID: peerId, Ephemeral: true, } diff --git a/management/server/file_store.go b/management/server/file_store.go index 73c52927e81..ee32d539764 100644 --- a/management/server/file_store.go +++ b/management/server/file_store.go @@ -10,6 +10,7 @@ import ( "github.com/rs/xid" log "github.com/sirupsen/logrus" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/telemetry" @@ -204,7 +205,7 @@ func restore(file string) (*FileStore, error) { // Set the Peer.ID to the newly generated value. // Replace all the mentions of Peer.Key as ID (groups and routes). // Swap Peer.Key with Peer.ID in the Account.Peers map. - migrationPeers := make(map[string]*Peer) // key to Peer + migrationPeers := make(map[string]*nbpeer.Peer) // key to Peer for key, peer := range account.Peers { // set LastLogin for the peers that were onboarded before the peer login expiration feature if peer.LastLogin.IsZero() { @@ -571,7 +572,7 @@ func (s *FileStore) SaveInstallationID(ID string) error { // SavePeerStatus stores the PeerStatus in memory. It doesn't attempt to persist data to speed up things. // PeerStatus will be saved eventually when some other changes occur. -func (s *FileStore) SavePeerStatus(accountID, peerID string, peerStatus PeerStatus) error { +func (s *FileStore) SavePeerStatus(accountID, peerID string, peerStatus nbpeer.PeerStatus) error { s.mux.Lock() defer s.mux.Unlock() diff --git a/management/server/file_store_test.go b/management/server/file_store_test.go index 206873d2022..eb2e2042b2c 100644 --- a/management/server/file_store_test.go +++ b/management/server/file_store_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/util" ) @@ -35,7 +36,7 @@ func TestStalePeerIndices(t *testing.T) { peerID := "some_peer" peerKey := "some_peer_key" - account.Peers[peerID] = &Peer{ + account.Peers[peerID] = &nbpeer.Peer{ ID: peerID, Key: peerKey, } @@ -89,13 +90,13 @@ func TestSaveAccount(t *testing.T) { account := newAccountWithId("account_id", "testuser", "") setupKey := GenerateDefaultSetupKey() account.SetupKeys[setupKey.Key] = setupKey - account.Peers["testpeer"] = &Peer{ + account.Peers["testpeer"] = &nbpeer.Peer{ Key: "peerkey", SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, } // SaveAccount should trigger persist @@ -125,13 +126,13 @@ func TestStore(t *testing.T) { store := newStore(t) account := newAccountWithId("account_id", "testuser", "") - account.Peers["testpeer"] = &Peer{ + account.Peers["testpeer"] = &nbpeer.Peer{ Key: "peerkey", SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, } account.Groups["all"] = &Group{ ID: "all", @@ -546,19 +547,19 @@ func TestFileStore_SavePeerStatus(t *testing.T) { } // save status of non-existing peer - newStatus := PeerStatus{Connected: true, LastSeen: time.Now().UTC()} + newStatus := nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()} err = store.SavePeerStatus(account.Id, "non-existing-peer", newStatus) assert.Error(t, err) // save new status of existing peer - account.Peers["testpeer"] = &Peer{ + account.Peers["testpeer"] = &nbpeer.Peer{ Key: "peerkey", ID: "testpeer", SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, } err = store.SaveAccount(account) diff --git a/management/server/grpcserver.go b/management/server/grpcserver.go index f32f6347a00..8d3d82661d0 100644 --- a/management/server/grpcserver.go +++ b/management/server/grpcserver.go @@ -17,6 +17,7 @@ import ( "github.com/netbirdio/netbird/encryption" "github.com/netbirdio/netbird/management/proto" "github.com/netbirdio/netbird/management/server/jwtclaims" + nbpeer "github.com/netbirdio/netbird/management/server/peer" internalStatus "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/telemetry" ) @@ -196,7 +197,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi } } -func (s *GRPCServer) cancelPeerRoutines(peer *Peer) { +func (s *GRPCServer) cancelPeerRoutines(peer *nbpeer.Peer) { s.peersUpdateManager.CloseChannel(peer.ID) s.turnCredentialsManager.CancelRefresh(peer.ID) _ = s.accountManager.MarkPeerConnected(peer.Key, false) @@ -243,8 +244,8 @@ func mapError(err error) error { return status.Errorf(codes.Internal, "failed handling request") } -func extractPeerMeta(loginReq *proto.LoginRequest) PeerSystemMeta { - return PeerSystemMeta{ +func extractPeerMeta(loginReq *proto.LoginRequest) nbpeer.PeerSystemMeta { + return nbpeer.PeerSystemMeta{ Hostname: loginReq.GetMeta().GetHostname(), GoOS: loginReq.GetMeta().GetGoOS(), Kernel: loginReq.GetMeta().GetKernel(), @@ -413,7 +414,7 @@ func toWiretrusteeConfig(config *Config, turnCredentials *TURNCredentials) *prot } } -func toPeerConfig(peer *Peer, network *Network, dnsName string) *proto.PeerConfig { +func toPeerConfig(peer *nbpeer.Peer, network *Network, dnsName string) *proto.PeerConfig { netmask, _ := network.Net.Mask.Size() fqdn := peer.FQDN(dnsName) return &proto.PeerConfig{ @@ -423,7 +424,7 @@ func toPeerConfig(peer *Peer, network *Network, dnsName string) *proto.PeerConfi } } -func toRemotePeerConfig(peers []*Peer, dnsName string) []*proto.RemotePeerConfig { +func toRemotePeerConfig(peers []*nbpeer.Peer, dnsName string) []*proto.RemotePeerConfig { remotePeers := []*proto.RemotePeerConfig{} for _, rPeer := range peers { fqdn := rPeer.FQDN(dnsName) @@ -437,7 +438,7 @@ func toRemotePeerConfig(peers []*Peer, dnsName string) []*proto.RemotePeerConfig return remotePeers } -func toSyncResponse(config *Config, peer *Peer, turnCredentials *TURNCredentials, networkMap *NetworkMap, dnsName string) *proto.SyncResponse { +func toSyncResponse(config *Config, peer *nbpeer.Peer, turnCredentials *TURNCredentials, networkMap *NetworkMap, dnsName string) *proto.SyncResponse { wtConfig := toWiretrusteeConfig(config, turnCredentials) pConfig := toPeerConfig(peer, networkMap.Network, dnsName) @@ -477,7 +478,7 @@ func (s *GRPCServer) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Em } // sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization -func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *Peer, networkMap *NetworkMap, srv proto.ManagementService_SyncServer) error { +func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *nbpeer.Peer, networkMap *NetworkMap, srv proto.ManagementService_SyncServer) error { // make secret time based TURN credentials optional var turnCredentials *TURNCredentials if s.config.TURNConfig.TimeBasedCredentials { diff --git a/management/server/http/peers_handler_test.go b/management/server/http/peers_handler_test.go index 673cd90c578..1690bb75f57 100644 --- a/management/server/http/peers_handler_test.go +++ b/management/server/http/peers_handler_test.go @@ -61,6 +61,7 @@ func initTestMetaData(peers ...*server.Peer) *PeersHandler { Domain: "hotmail.com", Peers: map[string]*server.Peer{ peers[0].ID: peers[0], + peers[1].ID: peers[1], }, Users: map[string]*server.User{ "test_user": user, @@ -112,7 +113,7 @@ func TestGetPeers(t *testing.T) { Key: "key", SetupKey: "setupkey", IP: net.ParseIP("100.64.0.1"), - Status: &server.PeerStatus{Connected: true}, + Status: &server.PeerStatus{Connected: true, Approved: true}, Name: "PeerName", LoginExpirationEnabled: false, Meta: server.PeerSystemMeta{ diff --git a/management/server/nameserver_test.go b/management/server/nameserver_test.go index d1f4cd01543..791dc567762 100644 --- a/management/server/nameserver_test.go +++ b/management/server/nameserver_test.go @@ -8,6 +8,7 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" ) const ( @@ -763,10 +764,10 @@ func createNSStore(t *testing.T) (Store, error) { func initTestNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) { t.Helper() - peer1 := &Peer{ + peer1 := &nbpeer.Peer{ Key: nsGroupPeer1Key, Name: "test-host1@netbird.io", - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host1@netbird.io", GoOS: "linux", Kernel: "Linux", @@ -777,10 +778,10 @@ func initTestNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, error UIVersion: "development", }, } - peer2 := &Peer{ + peer2 := &nbpeer.Peer{ Key: nsGroupPeer2Key, Name: "test-host2@netbird.io", - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host2@netbird.io", GoOS: "linux", Kernel: "Linux", diff --git a/management/server/network.go b/management/server/network.go index c5b165caeda..23ecb4c59d6 100644 --- a/management/server/network.go +++ b/management/server/network.go @@ -10,6 +10,7 @@ import ( "github.com/rs/xid" nbdns "github.com/netbirdio/netbird/dns" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/route" ) @@ -25,11 +26,11 @@ const ( ) type NetworkMap struct { - Peers []*Peer + Peers []*nbpeer.Peer Network *Network Routes []*route.Route DNSConfig nbdns.Config - OfflinePeers []*Peer + OfflinePeers []*nbpeer.Peer FirewallRules []*FirewallRule } diff --git a/management/server/peer.go b/management/server/peer.go index 6268ae7944b..97cada4f089 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -2,7 +2,6 @@ package server import ( "fmt" - "net" "strings" "time" @@ -10,6 +9,7 @@ import ( "github.com/rs/xid" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" log "github.com/sirupsen/logrus" @@ -17,40 +17,6 @@ import ( "github.com/netbirdio/netbird/management/proto" ) -// PeerSystemMeta is a metadata of a Peer machine system -type PeerSystemMeta struct { - Hostname string - GoOS string - Kernel string - Core string - Platform string - OS string - WtVersion string - UIVersion string -} - -func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool { - return p.Hostname == other.Hostname && - p.GoOS == other.GoOS && - p.Kernel == other.Kernel && - p.Core == other.Core && - p.Platform == other.Platform && - p.OS == other.OS && - p.WtVersion == other.WtVersion && - p.UIVersion == other.UIVersion -} - -type PeerStatus struct { - // LastSeen is the last time peer was connected to the management service - LastSeen time.Time - // Connected indicates whether peer is connected to the management service or not - Connected bool - // LoginExpired - LoginExpired bool - // RequiresApproval indicates whether peer requires approval or not - RequiresApproval bool -} - // PeerSync used as a data object between the gRPC API and AccountManager on Sync request. type PeerSync struct { // WireGuardPubKey is a peers WireGuard public key @@ -64,147 +30,16 @@ type PeerLogin struct { // SSHKey is a peer's ssh key. Can be empty (e.g., old version do not provide it, or this feature is disabled) SSHKey string // Meta is the system information passed by peer, must be always present. - Meta PeerSystemMeta + Meta nbpeer.PeerSystemMeta // UserID indicates that JWT was used to log in, and it was valid. Can be empty when SetupKey is used or auth is not required. UserID string // SetupKey references to a server.SetupKey to log in. Can be empty when UserID is used or auth is not required. SetupKey string } -// Peer represents a machine connected to the network. -// The Peer is a WireGuard peer identified by a public key -type Peer struct { - // ID is an internal ID of the peer - ID string `gorm:"primaryKey"` - // AccountID is a reference to Account that this object belongs - AccountID string `json:"-" gorm:"index;uniqueIndex:idx_peers_account_id_ip"` - // WireGuard public key - Key string `gorm:"index"` - // A setup key this peer was registered with - SetupKey string - // IP address of the Peer - IP net.IP `gorm:"uniqueIndex:idx_peers_account_id_ip"` - // Meta is a Peer system meta data - Meta PeerSystemMeta `gorm:"embedded;embeddedPrefix:meta_"` - // Name is peer's name (machine name) - Name string - // DNSLabel is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's - // domain to the peer label. e.g. peer-dns-label.netbird.cloud - DNSLabel string - // Status peer's management connection status - Status *PeerStatus `gorm:"embedded;embeddedPrefix:peer_status_"` - // The user ID that registered the peer - UserID string - // SSHKey is a public SSH key of the peer - SSHKey string - // SSHEnabled indicates whether SSH server is enabled on the peer - SSHEnabled bool - // LoginExpirationEnabled indicates whether peer's login expiration is enabled and once expired the peer has to re-login. - // Works with LastLogin - LoginExpirationEnabled bool - // LastLogin the time when peer performed last login operation - LastLogin time.Time - // Indicate ephemeral peer attribute - Ephemeral bool -} - -// AddedWithSSOLogin indicates whether this peer has been added with an SSO login by a user. -func (p *Peer) AddedWithSSOLogin() bool { - return p.UserID != "" -} - -// Copy copies Peer object -func (p *Peer) Copy() *Peer { - peerStatus := p.Status - if peerStatus != nil { - peerStatus = p.Status.Copy() - } - return &Peer{ - ID: p.ID, - AccountID: p.AccountID, - Key: p.Key, - SetupKey: p.SetupKey, - IP: p.IP, - Meta: p.Meta, - Name: p.Name, - DNSLabel: p.DNSLabel, - Status: peerStatus, - UserID: p.UserID, - SSHKey: p.SSHKey, - SSHEnabled: p.SSHEnabled, - LoginExpirationEnabled: p.LoginExpirationEnabled, - LastLogin: p.LastLogin, - Ephemeral: p.Ephemeral, - } -} - -// UpdateMetaIfNew updates peer's system metadata if new information is provided -// returns true if meta was updated, false otherwise -func (p *Peer) UpdateMetaIfNew(meta PeerSystemMeta) bool { - // Avoid overwriting UIVersion if the update was triggered sole by the CLI client - if meta.UIVersion == "" { - meta.UIVersion = p.Meta.UIVersion - } - - if p.Meta.isEqual(meta) { - return false - } - p.Meta = meta - return true -} - -// MarkLoginExpired marks peer's status expired or not -func (p *Peer) MarkLoginExpired(expired bool) { - newStatus := p.Status.Copy() - newStatus.LoginExpired = expired - if expired { - newStatus.Connected = false - } - p.Status = newStatus -} - -// LoginExpired indicates whether the peer's login has expired or not. -// If Peer.LastLogin plus the expiresIn duration has happened already; then login has expired. -// Return true if a login has expired, false otherwise, and time left to expiration (negative when expired). -// Login expiration can be disabled/enabled on a Peer level via Peer.LoginExpirationEnabled property. -// Login expiration can also be disabled/enabled globally on the Account level via Settings.PeerLoginExpirationEnabled. -// Only peers added by interactive SSO login can be expired. -func (p *Peer) LoginExpired(expiresIn time.Duration) (bool, time.Duration) { - if !p.AddedWithSSOLogin() || !p.LoginExpirationEnabled { - return false, 0 - } - expiresAt := p.LastLogin.Add(expiresIn) - now := time.Now() - timeLeft := expiresAt.Sub(now) - return timeLeft <= 0, timeLeft -} - -// FQDN returns peers FQDN combined of the peer's DNS label and the system's DNS domain -func (p *Peer) FQDN(dnsDomain string) string { - if dnsDomain == "" { - return "" - } - return fmt.Sprintf("%s.%s", p.DNSLabel, dnsDomain) -} - -// EventMeta returns activity event meta related to the peer -func (p *Peer) EventMeta(dnsDomain string) map[string]any { - return map[string]any{"name": p.Name, "fqdn": p.FQDN(dnsDomain), "ip": p.IP} -} - -// Copy PeerStatus -func (p *PeerStatus) Copy() *PeerStatus { - return &PeerStatus{ - LastSeen: p.LastSeen, - Connected: p.Connected, - LoginExpired: p.LoginExpired, - RequiresApproval: p.RequiresApproval, - } -} - // GetPeers returns a list of peers under the given account filtering out peers that do not belong to a user if // the current user is not an admin. -func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*Peer, error) { +func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*nbpeer.Peer, error) { account, err := am.Store.GetAccount(accountID) if err != nil { return nil, err @@ -215,8 +50,8 @@ func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*Peer, er return nil, err } - peers := make([]*Peer, 0) - peersMap := make(map[string]*Peer) + peers := make([]*nbpeer.Peer, 0) + peersMap := make(map[string]*nbpeer.Peer) for _, peer := range account.Peers { if !user.IsAdmin() && user.Id != peer.UserID { // only display peers that belong to the current user if the current user is not an admin @@ -235,7 +70,7 @@ func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*Peer, er } } - peers = make([]*Peer, 0, len(peersMap)) + peers = make([]*nbpeer.Peer, 0, len(peersMap)) for _, peer := range peersMap { peers = append(peers, peer) } @@ -294,7 +129,7 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerPubKey string, connected } // UpdatePeer updates peer. Only Peer.Name, Peer.SSHEnabled, and Peer.LoginExpirationEnabled can be updated. -func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Peer) (*Peer, error) { +func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *nbpeer.Peer) (*nbpeer.Peer, error) { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() @@ -373,7 +208,7 @@ func (am *DefaultAccountManager) deletePeers(account *Account, peerIDs []string, // the first loop is needed to ensure all peers present under the account before modifying, otherwise // we might have some inconsistencies - peers := make([]*Peer, 0, len(peerIDs)) + peers := make([]*nbpeer.Peer, 0, len(peerIDs)) for _, peerID := range peerIDs { peer := account.GetPeer(peerID) @@ -465,7 +300,7 @@ func (am *DefaultAccountManager) GetPeerNetwork(peerID string) (*Network, error) // to it. We also add the User ID to the peer metadata to identify registrant. If no userID provided, then fail with status.PermissionDenied // Each new Peer will be assigned a new next net.IP from the Account.Network and Account.Network.LastIP will be updated (IP's are not reused). // The peer property is just a placeholder for the Peer properties to pass further -func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*Peer, *NetworkMap, error) { +func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, *NetworkMap, error) { if setupKey == "" && userID == "" { // no auth method provided => reject access return nil, nil, status.Errorf(status.Unauthenticated, "no peer auth method provided, please use a setup key or interactive SSO login") @@ -554,7 +389,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (* return nil, nil, err } - newPeer := &Peer{ + newPeer := &nbpeer.Peer{ ID: xid.New().String(), Key: peer.Key, SetupKey: upperKey, @@ -563,7 +398,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (* Name: peer.Meta.Hostname, DNSLabel: newLabel, UserID: userID, - Status: &PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, SSHEnabled: false, SSHKey: peer.SSHKey, LastLogin: time.Now().UTC(), @@ -621,7 +456,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (* } // SyncPeer checks whether peer is eligible for receiving NetworkMap (authenticated) and returns its NetworkMap if eligible -func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*Peer, *NetworkMap, error) { +func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*nbpeer.Peer, *NetworkMap, error) { account, err := am.Store.GetAccountByPeerPubKey(sync.WireGuardPubKey) if err != nil { if errStatus, ok := status.FromError(err); ok && errStatus.Type() == status.NotFound { @@ -645,7 +480,7 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*Peer, *NetworkMap, er return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered") } - validatedPeers := integrations.ValidatePeers([]*Peer{peer}, account) + validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}, account) if len(validatedPeers) == 0 { return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed") } @@ -663,14 +498,14 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*Peer, *NetworkMap, er // LoginPeer logs in or registers a peer. // If peer doesn't exist the function checks whether a setup key or a user is present and registers a new peer if so. -func (am *DefaultAccountManager) LoginPeer(login PeerLogin) (*Peer, *NetworkMap, error) { +func (am *DefaultAccountManager) LoginPeer(login PeerLogin) (*nbpeer.Peer, *NetworkMap, error) { account, err := am.Store.GetAccountByPeerPubKey(login.WireGuardPubKey) if err != nil { if errStatus, ok := status.FromError(err); ok && errStatus.Type() == status.NotFound { // we couldn't find this peer by its public key which can mean that peer hasn't been registered yet. // Try registering it. - return am.AddPeer(login.SetupKey, login.UserID, &Peer{ + return am.AddPeer(login.SetupKey, login.UserID, &nbpeer.Peer{ Key: login.WireGuardPubKey, Meta: login.Meta, SSHKey: login.SSHKey, @@ -740,7 +575,7 @@ func (am *DefaultAccountManager) LoginPeer(login PeerLogin) (*Peer, *NetworkMap, return peer, account.GetPeerNetworkMap(peer.ID, am.dnsDomain), nil } -func checkIfPeerOwnerIsBlocked(peer *Peer, account *Account) error { +func checkIfPeerOwnerIsBlocked(peer *nbpeer.Peer, account *Account) error { if peer.AddedWithSSOLogin() { user, err := account.FindUser(peer.UserID) if err != nil { @@ -753,7 +588,7 @@ func checkIfPeerOwnerIsBlocked(peer *Peer, account *Account) error { return nil } -func checkAuth(loginUserID string, peer *Peer) error { +func checkAuth(loginUserID string, peer *nbpeer.Peer) error { if loginUserID == "" { // absence of a user ID indicates that JWT wasn't provided. return status.Errorf(status.PermissionDenied, "peer login has expired, please log in once more") @@ -765,7 +600,7 @@ func checkAuth(loginUserID string, peer *Peer) error { return nil } -func peerLoginExpired(peer *Peer, account *Account) bool { +func peerLoginExpired(peer *nbpeer.Peer, account *Account) bool { expired, expiresIn := peer.LoginExpired(account.Settings.PeerLoginExpiration) expired = account.Settings.PeerLoginExpirationEnabled && expired if expired || peer.Status.LoginExpired { @@ -775,21 +610,12 @@ func peerLoginExpired(peer *Peer, account *Account) bool { return false } -func updatePeerLastLogin(peer *Peer, account *Account) { +func updatePeerLastLogin(peer *nbpeer.Peer, account *Account) { peer.UpdateLastLogin() account.UpdatePeer(peer) } -// UpdateLastLogin and set login expired false -func (p *Peer) UpdateLastLogin() *Peer { - p.LastLogin = time.Now().UTC() - newStatus := p.Status.Copy() - newStatus.LoginExpired = false - p.Status = newStatus - return p -} - -func (am *DefaultAccountManager) checkAndUpdatePeerSSHKey(peer *Peer, account *Account, newSSHKey string) (*Peer, error) { +func (am *DefaultAccountManager) checkAndUpdatePeerSSHKey(peer *nbpeer.Peer, account *Account, newSSHKey string) (*nbpeer.Peer, error) { if len(newSSHKey) == 0 { log.Debugf("no new SSH key provided for peer %s, skipping update", peer.ID) return peer, nil @@ -860,7 +686,7 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(peerID string, sshKey string) } // GetPeer for a given accountID, peerID and userID error if not found. -func (am *DefaultAccountManager) GetPeer(accountID, peerID, userID string) (*Peer, error) { +func (am *DefaultAccountManager) GetPeer(accountID, peerID, userID string) (*nbpeer.Peer, error) { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() @@ -903,7 +729,7 @@ func (am *DefaultAccountManager) GetPeer(accountID, peerID, userID string) (*Pee return nil, status.Errorf(status.Internal, "user %s has no access to peer %s under account %s", userID, peerID, accountID) } -func updatePeerMeta(peer *Peer, meta PeerSystemMeta, account *Account) (*Peer, bool) { +func updatePeerMeta(peer *nbpeer.Peer, meta nbpeer.PeerSystemMeta, account *Account) (*nbpeer.Peer, bool) { if peer.UpdateMetaIfNew(meta) { account.UpdatePeer(peer) return peer, true diff --git a/management/server/peer/peer.go b/management/server/peer/peer.go new file mode 100644 index 00000000000..a4e4cc3aa36 --- /dev/null +++ b/management/server/peer/peer.go @@ -0,0 +1,181 @@ +package peer + +import ( + "fmt" + "net" + "time" +) + +// Peer represents a machine connected to the network. +// The Peer is a WireGuard peer identified by a public key +type Peer struct { + // ID is an internal ID of the peer + ID string `gorm:"primaryKey"` + // AccountID is a reference to Account that this object belongs + AccountID string `json:"-" gorm:"index;uniqueIndex:idx_peers_account_id_ip"` + // WireGuard public key + Key string `gorm:"index"` + // A setup key this peer was registered with + SetupKey string + // IP address of the Peer + IP net.IP `gorm:"uniqueIndex:idx_peers_account_id_ip"` + // Meta is a Peer system meta data + Meta PeerSystemMeta `gorm:"embedded;embeddedPrefix:meta_"` + // Name is peer's name (machine name) + Name string + // DNSLabel is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's + // domain to the peer label. e.g. peer-dns-label.netbird.cloud + DNSLabel string + // Status peer's management connection status + Status *PeerStatus `gorm:"embedded;embeddedPrefix:peer_status_"` + // The user ID that registered the peer + UserID string + // SSHKey is a public SSH key of the peer + SSHKey string + // SSHEnabled indicates whether SSH server is enabled on the peer + SSHEnabled bool + // LoginExpirationEnabled indicates whether peer's login expiration is enabled and once expired the peer has to re-login. + // Works with LastLogin + LoginExpirationEnabled bool + // LastLogin the time when peer performed last login operation + LastLogin time.Time + // Indicate ephemeral peer attribute + Ephemeral bool +} + +type PeerStatus struct { + // LastSeen is the last time peer was connected to the management service + LastSeen time.Time + // Connected indicates whether peer is connected to the management service or not + Connected bool + // LoginExpired + LoginExpired bool + // RequiresApproval indicates whether peer requires approval or not + RequiresApproval bool +} + +// PeerSystemMeta is a metadata of a Peer machine system +type PeerSystemMeta struct { + Hostname string + GoOS string + Kernel string + Core string + Platform string + OS string + WtVersion string + UIVersion string +} + +func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool { + return p.Hostname == other.Hostname && + p.GoOS == other.GoOS && + p.Kernel == other.Kernel && + p.Core == other.Core && + p.Platform == other.Platform && + p.OS == other.OS && + p.WtVersion == other.WtVersion && + p.UIVersion == other.UIVersion +} + +// AddedWithSSOLogin indicates whether this peer has been added with an SSO login by a user. +func (p *Peer) AddedWithSSOLogin() bool { + return p.UserID != "" +} + +// Copy copies Peer object +func (p *Peer) Copy() *Peer { + peerStatus := p.Status + if peerStatus != nil { + peerStatus = p.Status.Copy() + } + return &Peer{ + ID: p.ID, + AccountID: p.AccountID, + Key: p.Key, + SetupKey: p.SetupKey, + IP: p.IP, + Meta: p.Meta, + Name: p.Name, + DNSLabel: p.DNSLabel, + Status: peerStatus, + UserID: p.UserID, + SSHKey: p.SSHKey, + SSHEnabled: p.SSHEnabled, + LoginExpirationEnabled: p.LoginExpirationEnabled, + LastLogin: p.LastLogin, + Ephemeral: p.Ephemeral, + } +} + +// UpdateMetaIfNew updates peer's system metadata if new information is provided +// returns true if meta was updated, false otherwise +func (p *Peer) UpdateMetaIfNew(meta PeerSystemMeta) bool { + // Avoid overwriting UIVersion if the update was triggered sole by the CLI client + if meta.UIVersion == "" { + meta.UIVersion = p.Meta.UIVersion + } + + if p.Meta.isEqual(meta) { + return false + } + p.Meta = meta + return true +} + +// MarkLoginExpired marks peer's status expired or not +func (p *Peer) MarkLoginExpired(expired bool) { + newStatus := p.Status.Copy() + newStatus.LoginExpired = expired + if expired { + newStatus.Connected = false + } + p.Status = newStatus +} + +// LoginExpired indicates whether the peer's login has expired or not. +// If Peer.LastLogin plus the expiresIn duration has happened already; then login has expired. +// Return true if a login has expired, false otherwise, and time left to expiration (negative when expired). +// Login expiration can be disabled/enabled on a Peer level via Peer.LoginExpirationEnabled property. +// Login expiration can also be disabled/enabled globally on the Account level via Settings.PeerLoginExpirationEnabled. +// Only peers added by interactive SSO login can be expired. +func (p *Peer) LoginExpired(expiresIn time.Duration) (bool, time.Duration) { + if !p.AddedWithSSOLogin() || !p.LoginExpirationEnabled { + return false, 0 + } + expiresAt := p.LastLogin.Add(expiresIn) + now := time.Now() + timeLeft := expiresAt.Sub(now) + return timeLeft <= 0, timeLeft +} + +// FQDN returns peers FQDN combined of the peer's DNS label and the system's DNS domain +func (p *Peer) FQDN(dnsDomain string) string { + if dnsDomain == "" { + return "" + } + return fmt.Sprintf("%s.%s", p.DNSLabel, dnsDomain) +} + +// EventMeta returns activity event meta related to the peer +func (p *Peer) EventMeta(dnsDomain string) map[string]any { + return map[string]any{"name": p.Name, "fqdn": p.FQDN(dnsDomain), "ip": p.IP} +} + +// Copy PeerStatus +func (p *PeerStatus) Copy() *PeerStatus { + return &PeerStatus{ + LastSeen: p.LastSeen, + Connected: p.Connected, + LoginExpired: p.LoginExpired, + RequiresApproval: p.RequiresApproval, + } +} + +// UpdateLastLogin and set login expired false +func (p *Peer) UpdateLastLogin() *Peer { + p.LastLogin = time.Now().UTC() + newStatus := p.Status.Copy() + newStatus.LoginExpired = false + p.Status = newStatus + return p +} diff --git a/management/server/peer_test.go b/management/server/peer_test.go index 9d5a8bfb99d..ee84ea47dab 100644 --- a/management/server/peer_test.go +++ b/management/server/peer_test.go @@ -8,6 +8,8 @@ import ( "github.com/rs/xid" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + + nbpeer "github.com/netbirdio/netbird/management/server/peer" ) func TestPeer_LoginExpired(t *testing.T) { @@ -52,7 +54,7 @@ func TestPeer_LoginExpired(t *testing.T) { for _, c := range tt { t.Run(c.name, func(t *testing.T) { - peer := &Peer{ + peer := &nbpeer.Peer{ LoginExpirationEnabled: c.expirationEnabled, LastLogin: c.lastLogin, UserID: userID, @@ -90,9 +92,9 @@ func TestAccountManager_GetNetworkMap(t *testing.T) { return } - peer1, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer1, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey1.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-1"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -104,9 +106,9 @@ func TestAccountManager_GetNetworkMap(t *testing.T) { t.Fatal(err) return } - _, _, err = manager.AddPeer(setupKey.Key, "", &Peer{ + _, _, err = manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey2.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-2"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"}, }) if err != nil { @@ -163,9 +165,9 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) { return } - peer1, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer1, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey1.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-1"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -177,9 +179,9 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) { t.Fatal(err) return } - peer2, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer2, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey2.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-2"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -339,9 +341,9 @@ func TestAccountManager_GetPeerNetwork(t *testing.T) { return } - peer1, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer1, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey1.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-1"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -353,9 +355,9 @@ func TestAccountManager_GetPeerNetwork(t *testing.T) { t.Fatal(err) return } - _, _, err = manager.AddPeer(setupKey.Key, "", &Peer{ + _, _, err = manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey2.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-2"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"}, }) if err != nil { @@ -409,9 +411,9 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) { return } - peer1, _, err := manager.AddPeer("", someUser, &Peer{ + peer1, _, err := manager.AddPeer("", someUser, &nbpeer.Peer{ Key: peerKey1.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-2"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"}, }) if err != nil { t.Errorf("expecting peer to be added, got failure %v", err) @@ -425,9 +427,9 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) { } // the second peer added with a setup key - peer2, _, err := manager.AddPeer(setupKey.Key, "", &Peer{ + peer2, _, err := manager.AddPeer(setupKey.Key, "", &nbpeer.Peer{ Key: peerKey2.PublicKey().String(), - Meta: PeerSystemMeta{Hostname: "test-peer-2"}, + Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"}, }) if err != nil { t.Fatal(err) diff --git a/management/server/policy.go b/management/server/policy.go index 24188f93c01..dbfbca3abe9 100644 --- a/management/server/policy.go +++ b/management/server/policy.go @@ -9,6 +9,7 @@ import ( "github.com/netbirdio/netbird/management/proto" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" ) @@ -205,7 +206,7 @@ type FirewallRule struct { // getPeerConnectionResources for a given peer // // This function returns the list of peers and firewall rules that are applicable to a given peer. -func (a *Account) getPeerConnectionResources(peerID string) ([]*Peer, []*FirewallRule) { +func (a *Account) getPeerConnectionResources(peerID string) ([]*nbpeer.Peer, []*FirewallRule) { generateResources, getAccumulatedResources := a.connResourcesGenerator() for _, policy := range a.Policies { if !policy.Enabled { @@ -247,11 +248,11 @@ func (a *Account) getPeerConnectionResources(peerID string) ([]*Peer, []*Firewal // The generator function is used to generate the list of peers and firewall rules that are applicable to a given peer. // It safe to call the generator function multiple times for same peer and different rules no duplicates will be // generated. The accumulator function returns the result of all the generator calls. -func (a *Account) connResourcesGenerator() (func(*PolicyRule, []*Peer, int), func() ([]*Peer, []*FirewallRule)) { +func (a *Account) connResourcesGenerator() (func(*PolicyRule, []*nbpeer.Peer, int), func() ([]*nbpeer.Peer, []*FirewallRule)) { rulesExists := make(map[string]struct{}) peersExists := make(map[string]struct{}) rules := make([]*FirewallRule, 0) - peers := make([]*Peer, 0) + peers := make([]*nbpeer.Peer, 0) all, err := a.GetGroupAll() if err != nil { @@ -259,7 +260,7 @@ func (a *Account) connResourcesGenerator() (func(*PolicyRule, []*Peer, int), fun all = &Group{} } - return func(rule *PolicyRule, groupPeers []*Peer, direction int) { + return func(rule *PolicyRule, groupPeers []*nbpeer.Peer, direction int) { isAll := (len(all.Peers) - 1) == len(groupPeers) for _, peer := range groupPeers { if peer == nil { @@ -299,7 +300,7 @@ func (a *Account) connResourcesGenerator() (func(*PolicyRule, []*Peer, int), fun rules = append(rules, &pr) } } - }, func() ([]*Peer, []*FirewallRule) { + }, func() ([]*nbpeer.Peer, []*FirewallRule) { return peers, rules } } @@ -478,9 +479,9 @@ func toProtocolFirewallRules(update []*FirewallRule) []*proto.FirewallRule { // getAllPeersFromGroups for given peer ID and list of groups // // Returns list of peers and boolean indicating if peer is in any of the groups -func getAllPeersFromGroups(account *Account, groups []string, peerID string) ([]*Peer, bool) { +func getAllPeersFromGroups(account *Account, groups []string, peerID string) ([]*nbpeer.Peer, bool) { peerInGroups := false - filteredPeers := make([]*Peer, 0, len(groups)) + filteredPeers := make([]*nbpeer.Peer, 0, len(groups)) for _, g := range groups { group, ok := account.Groups[g] if !ok { diff --git a/management/server/policy_test.go b/management/server/policy_test.go index 971bd27d957..3ed08f4e6d7 100644 --- a/management/server/policy_test.go +++ b/management/server/policy_test.go @@ -7,11 +7,13 @@ import ( "github.com/stretchr/testify/assert" "golang.org/x/exp/slices" + + nbpeer "github.com/netbirdio/netbird/management/server/peer" ) func TestAccount_getPeersByPolicy(t *testing.T) { account := &Account{ - Peers: map[string]*Peer{ + Peers: map[string]*nbpeer.Peer{ "peerA": { ID: "peerA", IP: net.ParseIP("100.65.14.88"), @@ -255,7 +257,7 @@ func TestAccount_getPeersByPolicy(t *testing.T) { func TestAccount_getPeersByPolicyDirect(t *testing.T) { account := &Account{ - Peers: map[string]*Peer{ + Peers: map[string]*nbpeer.Peer{ "peerA": { ID: "peerA", IP: net.ParseIP("100.65.14.88"), diff --git a/management/server/route_test.go b/management/server/route_test.go index 5112a578042..94f169a9bf0 100644 --- a/management/server/route_test.go +++ b/management/server/route_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/netbirdio/netbird/management/server/activity" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/route" ) @@ -1045,13 +1046,13 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er return nil, err } - peer1 := &Peer{ + peer1 := &nbpeer.Peer{ IP: peer1IP, ID: peer1ID, Key: peer1Key, Name: "test-host1@netbird.io", UserID: userID, - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host1@netbird.io", GoOS: "linux", Kernel: "Linux", @@ -1070,13 +1071,13 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er return nil, err } - peer2 := &Peer{ + peer2 := &nbpeer.Peer{ IP: peer2IP, ID: peer2ID, Key: peer2Key, Name: "test-host2@netbird.io", UserID: userID, - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host2@netbird.io", GoOS: "linux", Kernel: "Linux", @@ -1095,13 +1096,13 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er return nil, err } - peer3 := &Peer{ + peer3 := &nbpeer.Peer{ IP: peer3IP, ID: peer3ID, Key: peer3Key, Name: "test-host3@netbird.io", UserID: userID, - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host3@netbird.io", GoOS: "darwin", Kernel: "Darwin", @@ -1120,13 +1121,13 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er return nil, err } - peer4 := &Peer{ + peer4 := &nbpeer.Peer{ IP: peer4IP, ID: peer4ID, Key: peer4Key, Name: "test-host4@netbird.io", UserID: userID, - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host4@netbird.io", GoOS: "linux", Kernel: "Linux", @@ -1145,13 +1146,13 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er return nil, err } - peer5 := &Peer{ + peer5 := &nbpeer.Peer{ IP: peer5IP, ID: peer5ID, Key: peer5Key, Name: "test-host4@netbird.io", UserID: userID, - Meta: PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "test-host4@netbird.io", GoOS: "linux", Kernel: "Linux", diff --git a/management/server/sqlite_store.go b/management/server/sqlite_store.go index bbb13f8c6db..abc3f575ad6 100644 --- a/management/server/sqlite_store.go +++ b/management/server/sqlite_store.go @@ -7,15 +7,17 @@ import ( "sync" "time" - nbdns "github.com/netbirdio/netbird/dns" - "github.com/netbirdio/netbird/management/server/status" - "github.com/netbirdio/netbird/management/server/telemetry" - "github.com/netbirdio/netbird/route" log "github.com/sirupsen/logrus" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/clause" "gorm.io/gorm/logger" + + nbdns "github.com/netbirdio/netbird/dns" + nbpeer "github.com/netbirdio/netbird/management/server/peer" + "github.com/netbirdio/netbird/management/server/status" + "github.com/netbirdio/netbird/management/server/telemetry" + "github.com/netbirdio/netbird/route" ) // SqliteStore represents an account storage backed by a Sqlite DB persisted to disk @@ -58,7 +60,7 @@ func NewSqliteStore(dataDir string, metrics telemetry.AppMetrics) (*SqliteStore, sql.SetMaxOpenConns(conns) // TODO: make it configurable err = db.AutoMigrate( - &SetupKey{}, &Peer{}, &User{}, &PersonalAccessToken{}, &Group{}, &Rule{}, + &SetupKey{}, &nbpeer.Peer{}, &User{}, &PersonalAccessToken{}, &Group{}, &Rule{}, &Account{}, &Policy{}, &PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{}, &installation{}, ) @@ -219,8 +221,8 @@ func (s *SqliteStore) GetInstallationID() string { return installation.InstallationIDValue } -func (s *SqliteStore) SavePeerStatus(accountID, peerID string, peerStatus PeerStatus) error { - var peer Peer +func (s *SqliteStore) SavePeerStatus(accountID, peerID string, peerStatus nbpeer.PeerStatus) error { + var peer nbpeer.Peer result := s.db.First(&peer, "account_id = ? and id = ?", accountID, peerID) if result.Error != nil { @@ -347,7 +349,7 @@ func (s *SqliteStore) GetAccount(accountID string) (*Account, error) { } account.SetupKeysG = nil - account.Peers = make(map[string]*Peer, len(account.PeersG)) + account.Peers = make(map[string]*nbpeer.Peer, len(account.PeersG)) for _, peer := range account.PeersG { account.Peers[peer.ID] = peer.Copy() } @@ -405,7 +407,7 @@ func (s *SqliteStore) GetAccountByUser(userID string) (*Account, error) { } func (s *SqliteStore) GetAccountByPeerID(peerID string) (*Account, error) { - var peer Peer + var peer nbpeer.Peer result := s.db.Select("account_id").First(&peer, "id = ?", peerID) if result.Error != nil { return nil, status.Errorf(status.NotFound, "account not found: index lookup failed") @@ -419,7 +421,7 @@ func (s *SqliteStore) GetAccountByPeerID(peerID string) (*Account, error) { } func (s *SqliteStore) GetAccountByPeerPubKey(peerKey string) (*Account, error) { - var peer Peer + var peer nbpeer.Peer result := s.db.Select("account_id").First(&peer, "key = ?", peerKey) if result.Error != nil { diff --git a/management/server/sqlite_store_test.go b/management/server/sqlite_store_test.go index 4a16e25255d..88d33001850 100644 --- a/management/server/sqlite_store_test.go +++ b/management/server/sqlite_store_test.go @@ -9,9 +9,11 @@ import ( "time" "github.com/google/uuid" - "github.com/netbirdio/netbird/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + nbpeer "github.com/netbirdio/netbird/management/server/peer" + "github.com/netbirdio/netbird/util" ) func TestSqlite_NewStore(t *testing.T) { @@ -36,13 +38,13 @@ func TestSqlite_SaveAccount(t *testing.T) { account := newAccountWithId("account_id", "testuser", "") setupKey := GenerateDefaultSetupKey() account.SetupKeys[setupKey.Key] = setupKey - account.Peers["testpeer"] = &Peer{ + account.Peers["testpeer"] = &nbpeer.Peer{ Key: "peerkey", SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, } err := store.SaveAccount(account) @@ -51,13 +53,13 @@ func TestSqlite_SaveAccount(t *testing.T) { account2 := newAccountWithId("account_id2", "testuser2", "") setupKey = GenerateDefaultSetupKey() account2.SetupKeys[setupKey.Key] = setupKey - account2.Peers["testpeer2"] = &Peer{ + account2.Peers["testpeer2"] = &nbpeer.Peer{ Key: "peerkey2", SetupKey: "peerkeysetupkey2", IP: net.IP{127, 0, 0, 2}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name 2", - Status: &PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, } err = store.SaveAccount(account2) @@ -109,19 +111,19 @@ func TestSqlite_SavePeerStatus(t *testing.T) { require.NoError(t, err) // save status of non-existing peer - newStatus := PeerStatus{Connected: true, LastSeen: time.Now().UTC()} + newStatus := nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()} err = store.SavePeerStatus(account.Id, "non-existing-peer", newStatus) assert.Error(t, err) // save new status of existing peer - account.Peers["testpeer"] = &Peer{ + account.Peers["testpeer"] = &nbpeer.Peer{ Key: "peerkey", ID: "testpeer", SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, } err = store.SaveAccount(account) @@ -216,13 +218,13 @@ func newAccount(store Store, id int) error { account := newAccountWithId(str, str+"-testuser", "example.com") setupKey := GenerateDefaultSetupKey() account.SetupKeys[setupKey.Key] = setupKey - account.Peers["p"+str] = &Peer{ + account.Peers["p"+str] = &nbpeer.Peer{ Key: "peerkey" + str, SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, } return store.SaveAccount(account) diff --git a/management/server/store.go b/management/server/store.go index 66b239f9614..2733a55f673 100644 --- a/management/server/store.go +++ b/management/server/store.go @@ -8,6 +8,7 @@ import ( log "github.com/sirupsen/logrus" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/telemetry" ) @@ -30,7 +31,7 @@ type Store interface { AcquireAccountLock(accountID string) func() // AcquireGlobalLock should attempt to acquire a global lock and return a function that releases the lock AcquireGlobalLock() func() - SavePeerStatus(accountID, peerID string, status PeerStatus) error + SavePeerStatus(accountID, peerID string, status nbpeer.PeerStatus) error SaveUserLastLogin(accountID, userID string, lastLogin time.Time) error // Close should close the store persisting all unsaved data. Close() error diff --git a/management/server/user.go b/management/server/user.go index b96bf743cda..821559f92a8 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -11,6 +11,7 @@ import ( "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/idp" "github.com/netbirdio/netbird/management/server/jwtclaims" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" ) @@ -980,7 +981,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) ( } // expireAndUpdatePeers expires all peers of the given user and updates them in the account -func (am *DefaultAccountManager) expireAndUpdatePeers(account *Account, peers []*Peer) error { +func (am *DefaultAccountManager) expireAndUpdatePeers(account *Account, peers []*nbpeer.Peer) error { var peerIDs []string for _, peer := range peers { if peer.Status.LoginExpired { From bab420ca77981af5606550e447b6635fcc5d9db6 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 28 Nov 2023 14:34:57 +0100 Subject: [PATCH 04/18] extract account into separate package --- management/server/account.go | 15 ++------------- management/server/account/account.go | 13 +++++++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 management/server/account/account.go diff --git a/management/server/account.go b/management/server/account.go index 1563570fa26..12198d7264f 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -24,6 +24,7 @@ import ( "github.com/netbirdio/netbird/base62" nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/idp" "github.com/netbirdio/netbird/management/server/jwtclaims" @@ -162,7 +163,7 @@ type Settings struct { JWTGroupsClaimName string // Extra is a dictionary of Account settings - Extra *ExtraSettings + Extra *account.ExtraSettings } // Copy copies the Settings struct @@ -180,18 +181,6 @@ func (s *Settings) Copy() *Settings { return settings } -type ExtraSettings struct { - // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator - PeerApprovalEnabled bool -} - -// Copy copies the ExtraSettings struct -func (e *ExtraSettings) Copy() *ExtraSettings { - return &ExtraSettings{ - PeerApprovalEnabled: e.PeerApprovalEnabled, - } -} - // Account represents a unique account of the system type Account struct { // we have to name column to aid as it collides with Network.Id when work with associations diff --git a/management/server/account/account.go b/management/server/account/account.go new file mode 100644 index 00000000000..b8b71a6de9e --- /dev/null +++ b/management/server/account/account.go @@ -0,0 +1,13 @@ +package account + +type ExtraSettings struct { + // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator + PeerApprovalEnabled bool +} + +// Copy copies the ExtraSettings struct +func (e *ExtraSettings) Copy() *ExtraSettings { + return &ExtraSettings{ + PeerApprovalEnabled: e.PeerApprovalEnabled, + } +} From ad1f18a52a1eaece4b7651de2c081fbe3fb6893a Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 28 Nov 2023 14:55:20 +0100 Subject: [PATCH 05/18] replace with updated integrations --- go.mod | 2 +- go.sum | 4 ++++ management/server/account.go | 6 +++--- management/server/peer.go | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 44d7cd6ec6f..cb8310dfb0c 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262 + github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pion/logging v0.2.2 diff --git a/go.sum b/go.sum index 4038f9b5fdd..5dcc3a77652 100644 --- a/go.sum +++ b/go.sum @@ -509,6 +509,10 @@ github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220- github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262 h1:JVImKBfZC2tC88GcJS0Hi6sdFL+FkhCcmbpU8lRAWss= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134203-547db8103a27 h1:cxyRuXtsr20HTz2YAcxpc+I1xVLLuIAxv8HpCs8Q5v4= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134203-547db8103a27/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06 h1:hEgJwiJTT/b0s3RNkXFpe2hTFu5rZJfHxd8UyuyRz/0= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949 h1:xbWM9BU6mwZZLHxEjxIX/V8Hv3HurQt4mReIE4mY4DM= diff --git a/management/server/account.go b/management/server/account.go index 12198d7264f..e4af8e8f680 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -360,14 +360,14 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { Network: a.Network.Copy(), } } - validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}, a) + validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}) if len(validatedPeers) == 0 { return &NetworkMap{ Network: a.Network.Copy(), } } aclPeers, firewallRules := a.getPeerConnectionResources(peerID) - aclPeers = integrations.ValidatePeers(aclPeers, a) + aclPeers = integrations.ValidatePeers(aclPeers) // exclude expired peers var peersToConnect []*nbpeer.Peer var expiredPeers []*nbpeer.Peer @@ -894,7 +894,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, return nil, err } - err = integrations.ValidateExtraSettings(newSettings.Extra, account, userID, am) + err = integrations.ValidateExtraSettings(newSettings.Extra, account.Settings.Extra, account.Peers, userID, accountID, am.eventStore) if err != nil { return nil, err } diff --git a/management/server/peer.go b/management/server/peer.go index 97cada4f089..b42615d1247 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -143,7 +143,7 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *nb return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID) } - update, err = integrations.ValidatePeersUpdateRequest(update, peer, am) + update, err = integrations.ValidatePeersUpdateRequest(update, peer, userID, am.eventStore, am.GetDNSDomain()) if err != nil { return nil, err } @@ -480,7 +480,7 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*nbpeer.Peer, *Network return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered") } - validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}, account) + validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}) if len(validatedPeers) == 0 { return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed") } From c829ad930c609cb0562638993e28c8a650007ed1 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 28 Nov 2023 15:09:04 +0100 Subject: [PATCH 06/18] use separate package for signatures --- go.mod | 3 ++- go.sum | 4 ++++ management/server/account.go | 8 ++++---- management/server/peer.go | 6 +++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index cb8310dfb0c..197bd8c2a67 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06 + github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pion/logging v0.2.2 @@ -120,6 +120,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/genetlink v1.1.0 // indirect github.com/mdlayher/netlink v1.7.1 // indirect + github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pegasus-kv/thrift v0.13.0 // indirect diff --git a/go.sum b/go.sum index 5dcc3a77652..8d9b2a92380 100644 --- a/go.sum +++ b/go.sum @@ -495,6 +495,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= +github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97 h1:bZWuD9M+xfslW+Abn8LJJ/S3gYQEwh+vQ4Sr9M8gcU4= +github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944 h1:n7o2/NCZzn0+73LGdl/VMh7DOTdWZ98le2woeZ4HlB0= github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40= github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a h1:6aipBr80s0GPKO9Wl+f5TUOSwebQ91uX2thk9tElyqc= @@ -513,6 +515,8 @@ github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134203- github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134203-547db8103a27/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06 h1:hEgJwiJTT/b0s3RNkXFpe2hTFu5rZJfHxd8UyuyRz/0= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 h1:2VmrReIXt4W45l7O93kzoTq7Bpn3CDGKhBwnqih0eao= +github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949 h1:xbWM9BU6mwZZLHxEjxIX/V8Hv3HurQt4mReIE4mY4DM= diff --git a/management/server/account.go b/management/server/account.go index e4af8e8f680..1dd128abd0f 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -17,7 +17,7 @@ import ( "github.com/eko/gocache/v3/cache" cacheStore "github.com/eko/gocache/v3/store" - "github.com/netbirdio/management-integrations/integrations" + "github.com/netbirdio/management-integrations/additions" gocache "github.com/patrickmn/go-cache" "github.com/rs/xid" log "github.com/sirupsen/logrus" @@ -360,14 +360,14 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { Network: a.Network.Copy(), } } - validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}) + validatedPeers := additions.ValidatePeers([]*nbpeer.Peer{peer}) if len(validatedPeers) == 0 { return &NetworkMap{ Network: a.Network.Copy(), } } aclPeers, firewallRules := a.getPeerConnectionResources(peerID) - aclPeers = integrations.ValidatePeers(aclPeers) + aclPeers = additions.ValidatePeers(aclPeers) // exclude expired peers var peersToConnect []*nbpeer.Peer var expiredPeers []*nbpeer.Peer @@ -894,7 +894,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string, return nil, err } - err = integrations.ValidateExtraSettings(newSettings.Extra, account.Settings.Extra, account.Peers, userID, accountID, am.eventStore) + err = additions.ValidateExtraSettings(newSettings.Extra, account.Settings.Extra, account.Peers, userID, accountID, am.eventStore) if err != nil { return nil, err } diff --git a/management/server/peer.go b/management/server/peer.go index b42615d1247..38a583a1e57 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/netbirdio/management-integrations/integrations" + "github.com/netbirdio/management-integrations/additions" "github.com/rs/xid" "github.com/netbirdio/netbird/management/server/activity" @@ -143,7 +143,7 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *nb return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID) } - update, err = integrations.ValidatePeersUpdateRequest(update, peer, userID, am.eventStore, am.GetDNSDomain()) + update, err = additions.ValidatePeersUpdateRequest(update, peer, userID, am.eventStore, am.GetDNSDomain()) if err != nil { return nil, err } @@ -480,7 +480,7 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*nbpeer.Peer, *Network return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered") } - validatedPeers := integrations.ValidatePeers([]*nbpeer.Peer{peer}) + validatedPeers := additions.ValidatePeers([]*nbpeer.Peer{peer}) if len(validatedPeers) == 0 { return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed") } From efd05ca0236cb4fa1cadcacaf90aefa8e94df032 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Tue, 28 Nov 2023 15:15:51 +0100 Subject: [PATCH 07/18] fix api references --- management/server/http/accounts_handler.go | 3 ++- management/server/http/groups_handler_test.go | 3 ++- management/server/http/peers_handler.go | 17 +++++++------- management/server/http/peers_handler_test.go | 23 ++++++++++--------- management/server/http/routes_handler_test.go | 7 +++--- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/management/server/http/accounts_handler.go b/management/server/http/accounts_handler.go index 8c356bb7ad4..ef7e2cdd2ed 100644 --- a/management/server/http/accounts_handler.go +++ b/management/server/http/accounts_handler.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/mux" "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" "github.com/netbirdio/netbird/management/server/jwtclaims" @@ -78,7 +79,7 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request) } if req.Settings.Extra != nil { - settings.Extra = &server.ExtraSettings{PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled} + settings.Extra = &account.ExtraSettings{PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled} } if req.Settings.JwtGroupsEnabled != nil { diff --git a/management/server/http/groups_handler_test.go b/management/server/http/groups_handler_test.go index 5f40be7a904..5b47b120861 100644 --- a/management/server/http/groups_handler_test.go +++ b/management/server/http/groups_handler_test.go @@ -19,10 +19,11 @@ import ( "github.com/netbirdio/netbird/management/server/http/util" "github.com/netbirdio/netbird/management/server/jwtclaims" "github.com/netbirdio/netbird/management/server/mock_server" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" ) -var TestPeers = map[string]*server.Peer{ +var TestPeers = map[string]*nbpeer.Peer{ "A": {Key: "A", ID: "peer-A-ID", IP: net.ParseIP("100.100.100.100")}, "B": {Key: "B", ID: "peer-B-ID", IP: net.ParseIP("200.200.200.200")}, } diff --git a/management/server/http/peers_handler.go b/management/server/http/peers_handler.go index c143a8076d3..46045868339 100644 --- a/management/server/http/peers_handler.go +++ b/management/server/http/peers_handler.go @@ -11,6 +11,7 @@ import ( "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" "github.com/netbirdio/netbird/management/server/jwtclaims" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" ) @@ -31,7 +32,7 @@ func NewPeersHandler(accountManager server.AccountManager, authCfg AuthCfg) *Pee } } -func (h *PeersHandler) checkPeerStatus(peer *server.Peer) (*server.Peer, error) { +func (h *PeersHandler) checkPeerStatus(peer *nbpeer.Peer) (*nbpeer.Peer, error) { peerToReturn := peer.Copy() if peer.Status.Connected { statuses, err := h.accountManager.GetAllConnectedPeers() @@ -79,11 +80,11 @@ func (h *PeersHandler) updatePeer(account *server.Account, user *server.User, pe return } - update := &server.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name, + update := &nbpeer.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name, LoginExpirationEnabled: req.LoginExpirationEnabled} if req.ApprovalRequired != nil { - update.Status = &server.PeerStatus{RequiresApproval: *req.ApprovalRequired} + update.Status = &nbpeer.PeerStatus{RequiresApproval: *req.ApprovalRequired} } peer, err := h.accountManager.UpdatePeer(account.Id, user.Id, update) @@ -234,7 +235,7 @@ func toGroupsInfo(groups map[string]*server.Group, peerID string) []api.GroupMin return groupsInfo } -func toSinglePeerResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeer []api.AccessiblePeer) *api.Peer { +func toSinglePeerResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeer []api.AccessiblePeer) *api.Peer { return &api.Peer{ Id: peer.ID, Name: peer.Name, @@ -253,11 +254,11 @@ func toSinglePeerResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dnsD LastLogin: peer.LastLogin, LoginExpired: peer.Status.LoginExpired, AccessiblePeers: accessiblePeer, - Approved: &peer.Status.Approved, + ApprovalRequired: &peer.Status.RequiresApproval, } } -func toPeerListItemResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeersCount int) *api.PeerBatch { +func toPeerListItemResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dnsDomain string, accessiblePeersCount int) *api.PeerBatch { return &api.PeerBatch{ Id: peer.ID, Name: peer.Name, @@ -276,11 +277,11 @@ func toPeerListItemResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dn LastLogin: peer.LastLogin, LoginExpired: peer.Status.LoginExpired, AccessiblePeersCount: accessiblePeersCount, - Approved: peer.Status.Approved, + ApprovalRequired: &peer.Status.RequiresApproval, } } -func fqdn(peer *server.Peer, dnsDomain string) string { +func fqdn(peer *nbpeer.Peer, dnsDomain string) string { fqdn := peer.FQDN(dnsDomain) if fqdn == "" { return peer.DNSLabel diff --git a/management/server/http/peers_handler_test.go b/management/server/http/peers_handler_test.go index 1690bb75f57..d13db447b6b 100644 --- a/management/server/http/peers_handler_test.go +++ b/management/server/http/peers_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/gorilla/mux" "github.com/netbirdio/netbird/management/server/http/api" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/jwtclaims" @@ -25,11 +26,11 @@ import ( const testPeerID = "test_peer" const noUpdateChannelTestPeerID = "no-update-channel" -func initTestMetaData(peers ...*server.Peer) *PeersHandler { +func initTestMetaData(peers ...*nbpeer.Peer) *PeersHandler { return &PeersHandler{ accountManager: &mock_server.MockAccountManager{ - UpdatePeerFunc: func(accountID, userID string, update *server.Peer) (*server.Peer, error) { - var p *server.Peer + UpdatePeerFunc: func(accountID, userID string, update *nbpeer.Peer) (*nbpeer.Peer, error) { + var p *nbpeer.Peer for _, peer := range peers { if update.ID == peer.ID { p = peer.Copy() @@ -41,8 +42,8 @@ func initTestMetaData(peers ...*server.Peer) *PeersHandler { p.Name = update.Name return p, nil }, - GetPeerFunc: func(accountID, peerID, userID string) (*server.Peer, error) { - var p *server.Peer + GetPeerFunc: func(accountID, peerID, userID string) (*nbpeer.Peer, error) { + var p *nbpeer.Peer for _, peer := range peers { if peerID == peer.ID { p = peer.Copy() @@ -51,7 +52,7 @@ func initTestMetaData(peers ...*server.Peer) *PeersHandler { } return p, nil }, - GetPeersFunc: func(accountID, userID string) ([]*server.Peer, error) { + GetPeersFunc: func(accountID, userID string) ([]*nbpeer.Peer, error) { return peers, nil }, GetAccountFromTokenFunc: func(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error) { @@ -59,7 +60,7 @@ func initTestMetaData(peers ...*server.Peer) *PeersHandler { return &server.Account{ Id: claims.AccountId, Domain: "hotmail.com", - Peers: map[string]*server.Peer{ + Peers: map[string]*nbpeer.Peer{ peers[0].ID: peers[0], peers[1].ID: peers[1], }, @@ -108,15 +109,15 @@ func initTestMetaData(peers ...*server.Peer) *PeersHandler { // Use the metadata generated by initTestMetaData() to check for values func TestGetPeers(t *testing.T) { - peer := &server.Peer{ + peer := &nbpeer.Peer{ ID: testPeerID, Key: "key", SetupKey: "setupkey", IP: net.ParseIP("100.64.0.1"), - Status: &server.PeerStatus{Connected: true, Approved: true}, + Status: &nbpeer.PeerStatus{Connected: true}, Name: "PeerName", LoginExpirationEnabled: false, - Meta: server.PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ Hostname: "hostname", GoOS: "GoOS", Kernel: "kernel", @@ -145,7 +146,7 @@ func TestGetPeers(t *testing.T) { requestPath string requestBody io.Reader expectedArray bool - expectedPeer *server.Peer + expectedPeer *nbpeer.Peer }{ { name: "GetPeersMetaData", diff --git a/management/server/http/routes_handler_test.go b/management/server/http/routes_handler_test.go index 0bb4587e4f4..c02292f2a94 100644 --- a/management/server/http/routes_handler_test.go +++ b/management/server/http/routes_handler_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/netbirdio/netbird/management/server/http/api" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/route" @@ -55,12 +56,12 @@ var baseExistingRoute = &route.Route{ var testingAccount = &server.Account{ Id: testAccountID, Domain: "hotmail.com", - Peers: map[string]*server.Peer{ + Peers: map[string]*nbpeer.Peer{ existingPeerID: { Key: existingPeerKey, IP: netip.MustParseAddr(existingPeerIP1).AsSlice(), ID: existingPeerID, - Meta: server.PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ GoOS: "linux", }, }, @@ -68,7 +69,7 @@ var testingAccount = &server.Account{ Key: nonLinuxExistingPeerID, IP: netip.MustParseAddr(existingPeerIP2).AsSlice(), ID: nonLinuxExistingPeerID, - Meta: server.PeerSystemMeta{ + Meta: nbpeer.PeerSystemMeta{ GoOS: "darwin", }, }, From 2129b23fe7630e3cc23b22416ccd322f67333f47 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 29 Nov 2023 14:56:06 +0100 Subject: [PATCH 08/18] allow sync for and return empty map --- management/server/peer.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/management/server/peer.go b/management/server/peer.go index 38a583a1e57..439756eb516 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -480,11 +480,6 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*nbpeer.Peer, *Network return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered") } - validatedPeers := additions.ValidatePeers([]*nbpeer.Peer{peer}) - if len(validatedPeers) == 0 { - return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed") - } - err = checkIfPeerOwnerIsBlocked(peer, account) if err != nil { return nil, nil, err From ba96e102b4d045da798eb423767c943547ed79d3 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 29 Nov 2023 15:16:11 +0100 Subject: [PATCH 09/18] settings nil check --- management/server/peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/management/server/peer.go b/management/server/peer.go index 439756eb516..00e97b0442e 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -406,7 +406,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P Ephemeral: ephemeral, } - if account.Settings.Extra.PeerApprovalEnabled { + if account.Settings.Extra != nil && account.Settings.Extra.PeerApprovalEnabled { newPeer.Status.RequiresApproval = true } From 8e74fb1fa82b68d62998040239121b3993525023 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 29 Nov 2023 15:57:56 +0100 Subject: [PATCH 10/18] add account id to validating peer update --- go.mod | 2 +- go.sum | 2 ++ management/server/peer.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 197bd8c2a67..2be225702b0 100644 --- a/go.mod +++ b/go.mod @@ -120,7 +120,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/genetlink v1.1.0 // indirect github.com/mdlayher/netlink v1.7.1 // indirect - github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97 // indirect + github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pegasus-kv/thrift v0.13.0 // indirect diff --git a/go.sum b/go.sum index 8d9b2a92380..bbe39de551c 100644 --- a/go.sum +++ b/go.sum @@ -497,6 +497,8 @@ github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97 h1:bZWuD9M+xfslW+Abn8LJJ/S3gYQEwh+vQ4Sr9M8gcU4= github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= +github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 h1:fNGkwtLHz0U4bP3bPVSwbtfL4I0ZVNYNCpmGwl6TETE= +github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944 h1:n7o2/NCZzn0+73LGdl/VMh7DOTdWZ98le2woeZ4HlB0= github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40= github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a h1:6aipBr80s0GPKO9Wl+f5TUOSwebQ91uX2thk9tElyqc= diff --git a/management/server/peer.go b/management/server/peer.go index 00e97b0442e..8fafb7b7162 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -143,7 +143,7 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *nb return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID) } - update, err = additions.ValidatePeersUpdateRequest(update, peer, userID, am.eventStore, am.GetDNSDomain()) + update, err = additions.ValidatePeersUpdateRequest(update, peer, userID, accountID, am.eventStore, am.GetDNSDomain()) if err != nil { return nil, err } From 96f866fb6802c06192bd23b2fe4197f73ba31672 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Wed, 29 Nov 2023 16:46:35 +0100 Subject: [PATCH 11/18] add missing imports after refactor --- go.mod | 2 +- go.sum | 20 ------------ management/server/metrics/selfhosted_test.go | 9 +++--- management/server/mock_server/account_mock.go | 31 ++++++++++--------- 4 files changed, 22 insertions(+), 40 deletions(-) diff --git a/go.mod b/go.mod index 2be225702b0..f3e9398527a 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 + github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -120,7 +121,6 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/genetlink v1.1.0 // indirect github.com/mdlayher/netlink v1.7.1 // indirect - github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pegasus-kv/thrift v0.13.0 // indirect diff --git a/go.sum b/go.sum index bbe39de551c..9407ba7b28b 100644 --- a/go.sum +++ b/go.sum @@ -495,28 +495,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= -github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97 h1:bZWuD9M+xfslW+Abn8LJJ/S3gYQEwh+vQ4Sr9M8gcU4= -github.com/netbirdio/management-integrations/additions v0.0.0-20231128140355-566178608e97/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 h1:fNGkwtLHz0U4bP3bPVSwbtfL4I0ZVNYNCpmGwl6TETE= github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944 h1:n7o2/NCZzn0+73LGdl/VMh7DOTdWZ98le2woeZ4HlB0= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a h1:6aipBr80s0GPKO9Wl+f5TUOSwebQ91uX2thk9tElyqc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683 h1:jJMO8KL2u3ok5VtGgZtFpuVK0GBEXXIb84idlmqGe68= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a h1:DIe9xdl6RcxeZFu5Pr3OPC8SHM6yadF212W3LJlzfhQ= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a h1:iMEPP7MC3/7DTs/BNMshsBoviG3yWSTRbIzXKdrUwHw= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 h1:PTQ2SSijkoN8Qkctq9oLzEdzCLLv7WoD2dqScmpb15o= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262 h1:JVImKBfZC2tC88GcJS0Hi6sdFL+FkhCcmbpU8lRAWss= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128110844-6dc8ff1bf262/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134203-547db8103a27 h1:cxyRuXtsr20HTz2YAcxpc+I1xVLLuIAxv8HpCs8Q5v4= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134203-547db8103a27/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06 h1:hEgJwiJTT/b0s3RNkXFpe2hTFu5rZJfHxd8UyuyRz/0= -github.com/netbirdio/management-integrations/integrations v0.0.0-20231128134945-092a9f4a2d06/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 h1:2VmrReIXt4W45l7O93kzoTq7Bpn3CDGKhBwnqih0eao= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= diff --git a/management/server/metrics/selfhosted_test.go b/management/server/metrics/selfhosted_test.go index 7717ff4094a..a577f8309d7 100644 --- a/management/server/metrics/selfhosted_test.go +++ b/management/server/metrics/selfhosted_test.go @@ -5,6 +5,7 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/route" ) @@ -37,12 +38,12 @@ func (mockDatasource) GetAllAccounts() []*server.Account { NameServerGroups: map[string]*nbdns.NameServerGroup{ "1": {}, }, - Peers: map[string]*server.Peer{ + Peers: map[string]*nbpeer.Peer{ "1": { ID: "1", UserID: "test", SSHEnabled: true, - Meta: server.PeerSystemMeta{GoOS: "linux", WtVersion: "0.0.1"}, + Meta: nbpeer.PeerSystemMeta{GoOS: "linux", WtVersion: "0.0.1"}, }, }, Policies: []*server.Policy{ @@ -101,12 +102,12 @@ func (mockDatasource) GetAllAccounts() []*server.Account { NameServerGroups: map[string]*nbdns.NameServerGroup{ "1": {}, }, - Peers: map[string]*server.Peer{ + Peers: map[string]*nbpeer.Peer{ "1": { ID: "1", UserID: "test", SSHEnabled: true, - Meta: server.PeerSystemMeta{GoOS: "linux", WtVersion: "0.0.1"}, + Meta: nbpeer.PeerSystemMeta{GoOS: "linux", WtVersion: "0.0.1"}, }, }, Policies: []*server.Policy{ diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index 84b23a4f257..b200af0c3a7 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -10,6 +10,7 @@ import ( "github.com/netbirdio/netbird/management/server" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/jwtclaims" + nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/route" ) @@ -21,12 +22,12 @@ type MockAccountManager struct { GetAccountByUserOrAccountIdFunc func(userId, accountId, domain string) (*server.Account, error) GetUserFunc func(claims jwtclaims.AuthorizationClaims) (*server.User, error) ListUsersFunc func(accountID string) ([]*server.User, error) - GetPeersFunc func(accountID, userID string) ([]*server.Peer, error) + GetPeersFunc func(accountID, userID string) ([]*nbpeer.Peer, error) MarkPeerConnectedFunc func(peerKey string, connected bool) error DeletePeerFunc func(accountID, peerKey, userID string) error GetNetworkMapFunc func(peerKey string) (*server.NetworkMap, error) GetPeerNetworkFunc func(peerKey string) (*server.Network, error) - AddPeerFunc func(setupKey string, userId string, peer *server.Peer) (*server.Peer, *server.NetworkMap, error) + AddPeerFunc func(setupKey string, userId string, peer *nbpeer.Peer) (*nbpeer.Peer, *server.NetworkMap, error) GetGroupFunc func(accountID, groupID string) (*server.Group, error) SaveGroupFunc func(accountID, userID string, group *server.Group) error DeleteGroupFunc func(accountID, userId, groupID string) error @@ -44,9 +45,9 @@ type MockAccountManager struct { GetUsersFromAccountFunc func(accountID, userID string) ([]*server.UserInfo, error) GetAccountFromPATFunc func(pat string) (*server.Account, *server.User, *server.PersonalAccessToken, error) MarkPATUsedFunc func(pat string) error - UpdatePeerMetaFunc func(peerID string, meta server.PeerSystemMeta) error + UpdatePeerMetaFunc func(peerID string, meta nbpeer.PeerSystemMeta) error UpdatePeerSSHKeyFunc func(peerID string, sshKey string) error - UpdatePeerFunc func(accountID, userID string, peer *server.Peer) (*server.Peer, error) + UpdatePeerFunc func(accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) CreateRouteFunc func(accountID, prefix, peer string, peerGroups []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) GetRouteFunc func(accountID, routeID, userID string) (*route.Route, error) SaveRouteFunc func(accountID, userID string, route *route.Route) error @@ -74,10 +75,10 @@ type MockAccountManager struct { GetEventsFunc func(accountID, userID string) ([]*activity.Event, error) GetDNSSettingsFunc func(accountID, userID string) (*server.DNSSettings, error) SaveDNSSettingsFunc func(accountID, userID string, dnsSettingsToSave *server.DNSSettings) error - GetPeerFunc func(accountID, peerID, userID string) (*server.Peer, error) + GetPeerFunc func(accountID, peerID, userID string) (*nbpeer.Peer, error) UpdateAccountSettingsFunc func(accountID, userID string, newSettings *server.Settings) (*server.Account, error) - LoginPeerFunc func(login server.PeerLogin) (*server.Peer, *server.NetworkMap, error) - SyncPeerFunc func(sync server.PeerSync) (*server.Peer, *server.NetworkMap, error) + LoginPeerFunc func(login server.PeerLogin) (*nbpeer.Peer, *server.NetworkMap, error) + SyncPeerFunc func(sync server.PeerSync) (*nbpeer.Peer, *server.NetworkMap, error) InviteUserFunc func(accountID string, initiatorUserID string, targetUserEmail string) error GetAllConnectedPeersFunc func() (map[string]struct{}, error) GetExternalCacheManagerFunc func() server.ExternalCacheManager @@ -226,8 +227,8 @@ func (am *MockAccountManager) GetPeerNetwork(peerKey string) (*server.Network, e func (am *MockAccountManager) AddPeer( setupKey string, userId string, - peer *server.Peer, -) (*server.Peer, *server.NetworkMap, error) { + peer *nbpeer.Peer, +) (*nbpeer.Peer, *server.NetworkMap, error) { if am.AddPeerFunc != nil { return am.AddPeerFunc(setupKey, userId, peer) } @@ -347,7 +348,7 @@ func (am *MockAccountManager) ListPolicies(accountID, userID string) ([]*server. } // UpdatePeerMeta mock implementation of UpdatePeerMeta from server.AccountManager interface -func (am *MockAccountManager) UpdatePeerMeta(peerID string, meta server.PeerSystemMeta) error { +func (am *MockAccountManager) UpdatePeerMeta(peerID string, meta nbpeer.PeerSystemMeta) error { if am.UpdatePeerMetaFunc != nil { return am.UpdatePeerMetaFunc(peerID, meta) } @@ -378,7 +379,7 @@ func (am *MockAccountManager) UpdatePeerSSHKey(peerID string, sshKey string) err } // UpdatePeer mocks UpdatePeerFunc function of the account manager -func (am *MockAccountManager) UpdatePeer(accountID, userID string, peer *server.Peer) (*server.Peer, error) { +func (am *MockAccountManager) UpdatePeer(accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) { if am.UpdatePeerFunc != nil { return am.UpdatePeerFunc(accountID, userID, peer) } @@ -542,7 +543,7 @@ func (am *MockAccountManager) GetAccountFromToken(claims jwtclaims.Authorization } // GetPeers mocks GetPeers of the AccountManager interface -func (am *MockAccountManager) GetPeers(accountID, userID string) ([]*server.Peer, error) { +func (am *MockAccountManager) GetPeers(accountID, userID string) ([]*nbpeer.Peer, error) { if am.GetAccountFromTokenFunc != nil { return am.GetPeersFunc(accountID, userID) } @@ -582,7 +583,7 @@ func (am *MockAccountManager) SaveDNSSettings(accountID string, userID string, d } // GetPeer mocks GetPeer of the AccountManager interface -func (am *MockAccountManager) GetPeer(accountID, peerID, userID string) (*server.Peer, error) { +func (am *MockAccountManager) GetPeer(accountID, peerID, userID string) (*nbpeer.Peer, error) { if am.GetPeerFunc != nil { return am.GetPeerFunc(accountID, peerID, userID) } @@ -598,7 +599,7 @@ func (am *MockAccountManager) UpdateAccountSettings(accountID, userID string, ne } // LoginPeer mocks LoginPeer of the AccountManager interface -func (am *MockAccountManager) LoginPeer(login server.PeerLogin) (*server.Peer, *server.NetworkMap, error) { +func (am *MockAccountManager) LoginPeer(login server.PeerLogin) (*nbpeer.Peer, *server.NetworkMap, error) { if am.LoginPeerFunc != nil { return am.LoginPeerFunc(login) } @@ -606,7 +607,7 @@ func (am *MockAccountManager) LoginPeer(login server.PeerLogin) (*server.Peer, * } // SyncPeer mocks SyncPeer of the AccountManager interface -func (am *MockAccountManager) SyncPeer(sync server.PeerSync) (*server.Peer, *server.NetworkMap, error) { +func (am *MockAccountManager) SyncPeer(sync server.PeerSync) (*nbpeer.Peer, *server.NetworkMap, error) { if am.SyncPeerFunc != nil { return am.SyncPeerFunc(sync) } From 47c44d4b875b178691cec7f3d168cea32e8dc493 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 30 Nov 2023 11:08:51 +0100 Subject: [PATCH 12/18] fix imports in sqlite store test --- management/server/sqlite_store_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/management/server/sqlite_store_test.go b/management/server/sqlite_store_test.go index cb2aa93b5ee..e493368fafe 100644 --- a/management/server/sqlite_store_test.go +++ b/management/server/sqlite_store_test.go @@ -117,13 +117,13 @@ func TestSqlite_DeleteAccount(t *testing.T) { account := newAccountWithId("account_id", testUserID, "") setupKey := GenerateDefaultSetupKey() account.SetupKeys[setupKey.Key] = setupKey - account.Peers["testpeer"] = &Peer{ + account.Peers["testpeer"] = &nbpeer.Peer{ Key: "peerkey", SetupKey: "peerkeysetupkey", IP: net.IP{127, 0, 0, 1}, - Meta: PeerSystemMeta{}, + Meta: nbpeer.PeerSystemMeta{}, Name: "peer name", - Status: &PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: true, LastSeen: time.Now().UTC()}, } account.Users[testUserID] = user From 4bf574037fe73d0fa9d1a925d081f6aba1fba8c4 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Thu, 30 Nov 2023 11:51:35 +0100 Subject: [PATCH 13/18] fix sql store --- management/server/account.go | 2 +- management/server/sqlite_store.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/management/server/account.go b/management/server/account.go index b95191b1f63..2ac00410ca5 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -164,7 +164,7 @@ type Settings struct { JWTGroupsClaimName string // Extra is a dictionary of Account settings - Extra *account.ExtraSettings + Extra *account.ExtraSettings `gorm:"embedded;embeddedPrefix:extra_"` } // Copy copies the Settings struct diff --git a/management/server/sqlite_store.go b/management/server/sqlite_store.go index 532597527f5..1bc2db3f17f 100644 --- a/management/server/sqlite_store.go +++ b/management/server/sqlite_store.go @@ -14,6 +14,7 @@ import ( "gorm.io/gorm/logger" nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/management/server/account" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/telemetry" @@ -62,7 +63,7 @@ func NewSqliteStore(dataDir string, metrics telemetry.AppMetrics) (*SqliteStore, err = db.AutoMigrate( &SetupKey{}, &nbpeer.Peer{}, &User{}, &PersonalAccessToken{}, &Group{}, &Rule{}, &Account{}, &Policy{}, &PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{}, - &installation{}, + &installation{}, &account.ExtraSettings{}, ) if err != nil { return nil, err From b9fc0085421e37276f754ee0487380eb6903a9ae Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 4 Dec 2023 12:49:36 +0100 Subject: [PATCH 14/18] extract peer preparation --- go.mod | 2 +- go.sum | 4 ++++ management/server/peer.go | 19 +++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index f3e9398527a..1d83be3b36f 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 + github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 9407ba7b28b..4474f9b4f15 100644 --- a/go.sum +++ b/go.sum @@ -497,6 +497,10 @@ github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 h1:fNGkwtLHz0U4bP3bPVSwbtfL4I0ZVNYNCpmGwl6TETE= github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204103019-ac6dd5a9c91c h1:LerqmkLL6OG+1n+wzxgXOx6kJZETUJVAvU5fZokUn9Q= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204103019-ac6dd5a9c91c/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f h1:yDNCzVwhgV05+D1sFmXCj9HEr2sob/MoWaGQLy3mKyY= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 h1:2VmrReIXt4W45l7O93kzoTq7Bpn3CDGKhBwnqih0eao= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= diff --git a/management/server/peer.go b/management/server/peer.go index 630a0154834..c025d7fd64d 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -406,16 +406,14 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P Ephemeral: ephemeral, } - if account.Settings.Extra != nil && account.Settings.Extra.PeerApprovalEnabled { - newPeer.Status.RequiresApproval = true - } + peerToAdd := additions.PreparePeer(newPeer, account.Settings) // add peer to 'All' group group, err := account.GetGroupAll() if err != nil { return nil, nil, err } - group.Peers = append(group.Peers, newPeer.ID) + group.Peers = append(group.Peers, peerToAdd.ID) var groupsToAdd []string if addedByUser { @@ -433,26 +431,27 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P if len(groupsToAdd) > 0 { for _, s := range groupsToAdd { if g, ok := account.Groups[s]; ok && g.Name != "All" { - g.Peers = append(g.Peers, newPeer.ID) + g.Peers = append(g.Peers, peerToAdd.ID) } } } - account.Peers[newPeer.ID] = newPeer + account.Peers[peerToAdd.ID] = newPeer account.Network.IncSerial() err = am.Store.SaveAccount(account) if err != nil { return nil, nil, err } - opEvent.TargetID = newPeer.ID - opEvent.Meta = newPeer.EventMeta(am.GetDNSDomain()) + opEvent.TargetID = peerToAdd.ID + opEvent.Meta = peerToAdd.EventMeta(am.GetDNSDomain()) + am.StoreEvent(opEvent.InitiatorID, opEvent.TargetID, opEvent.AccountID, opEvent.Activity, opEvent.Meta) am.updateAccountPeers(account) - networkMap := account.GetPeerNetworkMap(newPeer.ID, am.dnsDomain) - return newPeer, networkMap, nil + networkMap := account.GetPeerNetworkMap(peerToAdd.ID, am.dnsDomain) + return peerToAdd, networkMap, nil } // SyncPeer checks whether peer is eligible for receiving NetworkMap (authenticated) and returns its NetworkMap if eligible From 89249b414f136c5a7eeb400d97570d5a2d9390b9 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 4 Dec 2023 14:53:38 +0100 Subject: [PATCH 15/18] move peer validation into getPeerconnectionResources --- management/server/account.go | 1 - management/server/policy.go | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/management/server/account.go b/management/server/account.go index 14fd241a170..baaea2005d1 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -368,7 +368,6 @@ func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap { } } aclPeers, firewallRules := a.getPeerConnectionResources(peerID) - aclPeers = additions.ValidatePeers(aclPeers) // exclude expired peers var peersToConnect []*nbpeer.Peer var expiredPeers []*nbpeer.Peer diff --git a/management/server/policy.go b/management/server/policy.go index 37718a3e0ff..0eb2fb5385c 100644 --- a/management/server/policy.go +++ b/management/server/policy.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "github.com/netbirdio/management-integrations/additions" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/management/proto" @@ -220,6 +221,8 @@ func (a *Account) getPeerConnectionResources(peerID string) ([]*nbpeer.Peer, []* sourcePeers, peerInSources := getAllPeersFromGroups(a, rule.Sources, peerID) destinationPeers, peerInDestinations := getAllPeersFromGroups(a, rule.Destinations, peerID) + sourcePeers = additions.ValidatePeers(sourcePeers) + destinationPeers = additions.ValidatePeers(destinationPeers) if rule.Bidirectional { if peerInSources { From dc8f55f23e925061847d59236f191763434b5d9a Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 4 Dec 2023 16:26:34 +0100 Subject: [PATCH 16/18] remove dependency cycle from prepare peer --- go.mod | 2 +- go.sum | 4 ++++ management/server/peer.go | 18 ++++++++++-------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 1d83be3b36f..12b7d9a95fb 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/miekg/dns v1.1.43 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f + github.com/netbirdio/management-integrations/additions v0.0.0-20231204152258-2328ed53de48 github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/patrickmn/go-cache v2.1.0+incompatible diff --git a/go.sum b/go.sum index 4474f9b4f15..b0fdfecfd68 100644 --- a/go.sum +++ b/go.sum @@ -501,6 +501,10 @@ github.com/netbirdio/management-integrations/additions v0.0.0-20231204103019-ac6 github.com/netbirdio/management-integrations/additions v0.0.0-20231204103019-ac6dd5a9c91c/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f h1:yDNCzVwhgV05+D1sFmXCj9HEr2sob/MoWaGQLy3mKyY= github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204151811-a5cf1000bdd4 h1:ApjFM/CU3My4lLL1HVb0j7q4+jmXdbYFVT8RJNLQjyc= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204151811-a5cf1000bdd4/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204152258-2328ed53de48 h1:TEaiKhkxwIFA2AmIj/7x9X/6zlXjV68Vs6Wclew1oTs= +github.com/netbirdio/management-integrations/additions v0.0.0-20231204152258-2328ed53de48/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 h1:2VmrReIXt4W45l7O93kzoTq7Bpn3CDGKhBwnqih0eao= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97/go.mod h1:eRv50kd3bXd2y59HK3OY4RI8YUL0JEN290D5dqW4llY= github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g= diff --git a/management/server/peer.go b/management/server/peer.go index c025d7fd64d..de7ce263ece 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -406,14 +406,16 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P Ephemeral: ephemeral, } - peerToAdd := additions.PreparePeer(newPeer, account.Settings) + if account.Settings.Extra != nil { + newPeer = additions.PreparePeer(newPeer, account.Settings.Extra) + } // add peer to 'All' group group, err := account.GetGroupAll() if err != nil { return nil, nil, err } - group.Peers = append(group.Peers, peerToAdd.ID) + group.Peers = append(group.Peers, newPeer.ID) var groupsToAdd []string if addedByUser { @@ -431,27 +433,27 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P if len(groupsToAdd) > 0 { for _, s := range groupsToAdd { if g, ok := account.Groups[s]; ok && g.Name != "All" { - g.Peers = append(g.Peers, peerToAdd.ID) + g.Peers = append(g.Peers, newPeer.ID) } } } - account.Peers[peerToAdd.ID] = newPeer + account.Peers[newPeer.ID] = newPeer account.Network.IncSerial() err = am.Store.SaveAccount(account) if err != nil { return nil, nil, err } - opEvent.TargetID = peerToAdd.ID - opEvent.Meta = peerToAdd.EventMeta(am.GetDNSDomain()) + opEvent.TargetID = newPeer.ID + opEvent.Meta = newPeer.EventMeta(am.GetDNSDomain()) am.StoreEvent(opEvent.InitiatorID, opEvent.TargetID, opEvent.AccountID, opEvent.Activity, opEvent.Meta) am.updateAccountPeers(account) - networkMap := account.GetPeerNetworkMap(peerToAdd.ID, am.dnsDomain) - return peerToAdd, networkMap, nil + networkMap := account.GetPeerNetworkMap(newPeer.ID, am.dnsDomain) + return newPeer, networkMap, nil } // SyncPeer checks whether peer is eligible for receiving NetworkMap (authenticated) and returns its NetworkMap if eligible From 7a18dea7667e8d5b36c0c6162ed1c29861c30263 Mon Sep 17 00:00:00 2001 From: Pascal Fischer Date: Mon, 4 Dec 2023 17:35:49 +0100 Subject: [PATCH 17/18] go mod tidy --- go.sum | 8 -------- 1 file changed, 8 deletions(-) diff --git a/go.sum b/go.sum index b0fdfecfd68..27f48b31ee5 100644 --- a/go.sum +++ b/go.sum @@ -495,14 +495,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= -github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2 h1:fNGkwtLHz0U4bP3bPVSwbtfL4I0ZVNYNCpmGwl6TETE= -github.com/netbirdio/management-integrations/additions v0.0.0-20231129145353-f46b1dd842f2/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= -github.com/netbirdio/management-integrations/additions v0.0.0-20231204103019-ac6dd5a9c91c h1:LerqmkLL6OG+1n+wzxgXOx6kJZETUJVAvU5fZokUn9Q= -github.com/netbirdio/management-integrations/additions v0.0.0-20231204103019-ac6dd5a9c91c/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= -github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f h1:yDNCzVwhgV05+D1sFmXCj9HEr2sob/MoWaGQLy3mKyY= -github.com/netbirdio/management-integrations/additions v0.0.0-20231204103351-c9d8082fc22f/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= -github.com/netbirdio/management-integrations/additions v0.0.0-20231204151811-a5cf1000bdd4 h1:ApjFM/CU3My4lLL1HVb0j7q4+jmXdbYFVT8RJNLQjyc= -github.com/netbirdio/management-integrations/additions v0.0.0-20231204151811-a5cf1000bdd4/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/additions v0.0.0-20231204152258-2328ed53de48 h1:TEaiKhkxwIFA2AmIj/7x9X/6zlXjV68Vs6Wclew1oTs= github.com/netbirdio/management-integrations/additions v0.0.0-20231204152258-2328ed53de48/go.mod h1:31FhBNvQ+riHEIu6LSTmqr8IeuSIsGfQffqV4LFmbwA= github.com/netbirdio/management-integrations/integrations v0.0.0-20231128140355-566178608e97 h1:2VmrReIXt4W45l7O93kzoTq7Bpn3CDGKhBwnqih0eao= From 0d2db4b172a0c4de9306b696deb337feabf10edc Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Mon, 4 Dec 2023 19:02:16 +0100 Subject: [PATCH 18/18] update API doc --- management/server/http/api/openapi.yml | 2 +- management/server/http/api/types.gen.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/management/server/http/api/openapi.yml b/management/server/http/api/openapi.yml index cf48fe4f829..2b8d614f639 100644 --- a/management/server/http/api/openapi.yml +++ b/management/server/http/api/openapi.yml @@ -75,7 +75,7 @@ components: type: object properties: peer_approval_enabled: - description: Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. + description: (Cloud only) Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. type: boolean example: true AccountRequest: diff --git a/management/server/http/api/types.gen.go b/management/server/http/api/types.gen.go index 5298e887bf0..8e41f567249 100644 --- a/management/server/http/api/types.gen.go +++ b/management/server/http/api/types.gen.go @@ -144,7 +144,7 @@ type Account struct { // AccountExtraSettings defines model for AccountExtraSettings. type AccountExtraSettings struct { - // PeerApprovalEnabled Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. + // PeerApprovalEnabled (Cloud only) Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. PeerApprovalEnabled *bool `json:"peer_approval_enabled,omitempty"` }