2021-08-23 21:43:05 +02:00
package server
import (
2024-07-03 11:33:02 +02:00
"context"
2023-01-02 15:11:32 +01:00
"fmt"
2024-02-20 09:59:56 +01:00
"net"
2021-08-23 21:43:05 +02:00
"strings"
2024-08-07 10:52:31 +02:00
"sync"
2021-08-23 21:43:05 +02:00
"time"
2022-05-21 15:21:39 +02:00
2023-04-03 15:09:35 +02:00
"github.com/rs/xid"
2024-03-27 18:48:48 +01:00
log "github.com/sirupsen/logrus"
2023-04-03 15:09:35 +02:00
2024-07-26 07:49:05 +02:00
"github.com/netbirdio/netbird/management/server/posture"
2024-03-27 18:48:48 +01:00
"github.com/netbirdio/netbird/management/proto"
2023-03-13 15:14:18 +01:00
"github.com/netbirdio/netbird/management/server/activity"
2023-11-28 13:45:26 +01:00
nbpeer "github.com/netbirdio/netbird/management/server/peer"
2023-03-13 15:14:18 +01:00
"github.com/netbirdio/netbird/management/server/status"
2021-08-23 21:43:05 +02:00
)
2023-03-03 18:35:38 +01:00
// 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
WireGuardPubKey string
2024-06-13 13:24:24 +02:00
// Meta is the system information passed by peer, must be always present
Meta nbpeer . PeerSystemMeta
// UpdateAccountPeers indicate updating account peers,
// which occurs when the peer's metadata is updated
UpdateAccountPeers bool
2023-03-03 18:35:38 +01:00
}
// PeerLogin used as a data object between the gRPC API and AccountManager on Login request.
type PeerLogin struct {
// WireGuardPubKey is a peers WireGuard public key
WireGuardPubKey string
// 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.
2023-11-28 13:45:26 +01:00
Meta nbpeer . PeerSystemMeta
2023-03-03 18:35:38 +01:00
// 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
2024-03-27 18:48:48 +01:00
// ConnectionIP is the real IP of the peer
ConnectionIP net . IP
2023-03-03 18:35:38 +01:00
}
2022-11-05 10:24:50 +01:00
// 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.
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) GetPeers ( ctx context . Context , accountID , userID string ) ( [ ] * nbpeer . Peer , error ) {
account , err := am . Store . GetAccount ( ctx , accountID )
2022-11-05 10:24:50 +01:00
if err != nil {
return nil , err
}
user , err := account . FindUser ( userID )
if err != nil {
return nil , err
}
2024-03-27 18:48:48 +01:00
approvedPeersMap , err := am . GetValidatedPeers ( account )
if err != nil {
return nil , err
}
2023-11-28 13:45:26 +01:00
peers := make ( [ ] * nbpeer . Peer , 0 )
peersMap := make ( map [ string ] * nbpeer . Peer )
2024-03-27 16:11:45 +01:00
2024-08-07 10:22:12 +02:00
regularUser := ! user . HasAdminPower ( ) && ! user . IsServiceUser
if regularUser && account . Settings . RegularUsersViewBlocked {
2024-03-27 16:11:45 +01:00
return peers , nil
}
2022-11-05 10:24:50 +01:00
for _ , peer := range account . Peers {
2024-08-07 10:22:12 +02:00
if regularUser && user . Id != peer . UserID {
2022-11-05 10:24:50 +01:00
// only display peers that belong to the current user if the current user is not an admin
continue
}
2022-11-21 17:45:14 +01:00
p := peer . Copy ( )
peers = append ( peers , p )
2023-02-03 10:33:28 +01:00
peersMap [ peer . ID ] = p
2022-11-21 17:45:14 +01:00
}
2024-08-07 10:22:12 +02:00
if ! regularUser {
return peers , nil
}
2022-11-21 17:45:14 +01:00
// fetch all the peers that have access to the user's peers
for _ , peer := range peers {
2024-07-03 11:33:02 +02:00
aclPeers , _ := account . getPeerConnectionResources ( ctx , peer . ID , approvedPeersMap )
2022-11-21 17:45:14 +01:00
for _ , p := range aclPeers {
2023-02-03 10:33:28 +01:00
peersMap [ p . ID ] = p
2022-11-21 17:45:14 +01:00
}
}
2023-11-28 13:45:26 +01:00
peers = make ( [ ] * nbpeer . Peer , 0 , len ( peersMap ) )
2022-11-21 17:45:14 +01:00
for _ , peer := range peersMap {
peers = append ( peers , peer )
2022-11-05 10:24:50 +01:00
}
return peers , nil
}
2022-05-21 15:21:39 +02:00
// MarkPeerConnected marks peer as connected (true) or disconnected (false)
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) MarkPeerConnected ( ctx context . Context , peerPubKey string , connected bool , realIP net . IP , account * Account ) error {
2022-11-07 12:10:56 +01:00
peer , err := account . FindPeerByPubKey ( peerPubKey )
2021-08-24 11:50:19 +02:00
if err != nil {
return err
}
2023-02-27 16:44:26 +01:00
oldStatus := peer . Status . Copy ( )
newStatus := oldStatus
2023-04-03 15:09:35 +02:00
newStatus . LastSeen = time . Now ( ) . UTC ( )
2022-11-08 10:46:12 +01:00
newStatus . Connected = connected
2023-02-15 11:27:22 +01:00
// whenever peer got connected that means that it logged in successfully
if newStatus . Connected {
newStatus . LoginExpired = false
}
2022-11-08 10:46:12 +01:00
peer . Status = newStatus
2024-02-20 09:59:56 +01:00
if am . geo != nil && realIP != nil {
location , err := am . geo . Lookup ( realIP )
if err != nil {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Warnf ( "failed to get location for peer %s realip: [%s]: %v" , peer . ID , realIP . String ( ) , err )
2024-02-20 09:59:56 +01:00
} else {
peer . Location . ConnectionIP = realIP
peer . Location . CountryCode = location . Country . ISOCode
peer . Location . CityName = location . City . Names . En
peer . Location . GeoNameID = location . City . GeonameID
err = am . Store . SavePeerLocation ( account . Id , peer )
if err != nil {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Warnf ( "could not store location for peer %s: %s" , peer . ID , err )
2024-02-20 09:59:56 +01:00
}
}
}
2022-11-07 12:10:56 +01:00
account . UpdatePeer ( peer )
2023-02-03 10:33:28 +01:00
err = am . Store . SavePeerStatus ( account . Id , peer . ID , * newStatus )
2021-08-24 11:50:19 +02:00
if err != nil {
return err
}
2023-02-27 16:44:26 +01:00
if peer . AddedWithSSOLogin ( ) && peer . LoginExpirationEnabled && account . Settings . PeerLoginExpirationEnabled {
2024-07-03 11:33:02 +02:00
am . checkAndSchedulePeerLoginExpiration ( ctx , account )
2023-02-27 16:44:26 +01:00
}
if oldStatus . LoginExpired {
// we need to update other peers because when peer login expires all other peers are notified to disconnect from
2023-03-13 15:14:18 +01:00
// the expired one. Here we notify them that connection is now allowed again.
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2023-02-27 16:44:26 +01:00
}
2021-08-24 11:50:19 +02:00
return nil
}
2023-02-14 10:14:00 +01:00
// UpdatePeer updates peer. Only Peer.Name, Peer.SSHEnabled, and Peer.LoginExpirationEnabled can be updated.
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) UpdatePeer ( ctx context . Context , accountID , userID string , update * nbpeer . Peer ) ( * nbpeer . Peer , error ) {
2024-07-31 14:53:32 +02:00
unlock := am . Store . AcquireWriteLockByUID ( ctx , accountID )
2022-11-07 17:52:23 +01:00
defer unlock ( )
2022-06-23 17:04:53 +02:00
2024-07-03 11:33:02 +02:00
account , err := am . Store . GetAccount ( ctx , accountID )
2022-06-23 17:04:53 +02:00
if err != nil {
2022-11-11 20:36:45 +01:00
return nil , err
2022-06-23 17:04:53 +02:00
}
2023-02-03 10:33:28 +01:00
peer := account . GetPeer ( update . ID )
if peer == nil {
return nil , status . Errorf ( status . NotFound , "peer %s not found" , update . ID )
2022-06-23 17:04:53 +02:00
}
2024-07-03 11:33:02 +02:00
update , err = am . integratedPeerValidator . ValidatePeer ( ctx , update , peer , userID , accountID , am . GetDNSDomain ( ) , account . GetPeerGroupsList ( peer . ID ) , account . Settings . Extra )
2023-11-28 11:44:08 +01:00
if err != nil {
return nil , err
}
2023-01-25 16:29:59 +01:00
if peer . SSHEnabled != update . SSHEnabled {
peer . SSHEnabled = update . SSHEnabled
event := activity . PeerSSHEnabled
if ! update . SSHEnabled {
event = activity . PeerSSHDisabled
}
2024-07-03 11:33:02 +02:00
am . StoreEvent ( ctx , userID , peer . IP . String ( ) , accountID , event , peer . EventMeta ( am . GetDNSDomain ( ) ) )
2023-01-25 16:29:59 +01:00
}
2022-06-23 17:04:53 +02:00
2023-01-20 10:07:37 +01:00
if peer . Name != update . Name {
peer . Name = update . Name
2022-11-07 15:38:21 +01:00
2023-01-20 10:07:37 +01:00
existingLabels := account . getPeerDNSLabels ( )
newLabel , err := getPeerHostLabel ( peer . Name , existingLabels )
if err != nil {
return nil , err
}
2022-11-07 15:38:21 +01:00
2023-01-20 10:07:37 +01:00
peer . DNSLabel = newLabel
2023-01-25 16:29:59 +01:00
2024-07-03 11:33:02 +02:00
am . StoreEvent ( ctx , userID , peer . ID , accountID , activity . PeerRenamed , peer . EventMeta ( am . GetDNSDomain ( ) ) )
2023-01-20 10:07:37 +01:00
}
2022-11-07 15:38:21 +01:00
2023-02-14 10:14:00 +01:00
if peer . LoginExpirationEnabled != update . LoginExpirationEnabled {
2023-02-16 13:03:53 +01:00
if ! peer . AddedWithSSOLogin ( ) {
return nil , status . Errorf ( status . PreconditionFailed , "this peer hasn't been added with the SSO login, therefore the login expiration can't be updated" )
}
2023-02-14 10:14:00 +01:00
peer . LoginExpirationEnabled = update . LoginExpirationEnabled
event := activity . PeerLoginExpirationEnabled
if ! update . LoginExpirationEnabled {
event = activity . PeerLoginExpirationDisabled
}
2024-07-03 11:33:02 +02:00
am . StoreEvent ( ctx , userID , peer . IP . String ( ) , accountID , event , peer . EventMeta ( am . GetDNSDomain ( ) ) )
2023-02-27 16:44:26 +01:00
if peer . AddedWithSSOLogin ( ) && peer . LoginExpirationEnabled && account . Settings . PeerLoginExpirationEnabled {
2024-07-03 11:33:02 +02:00
am . checkAndSchedulePeerLoginExpiration ( ctx , account )
2023-02-27 16:44:26 +01:00
}
2023-02-14 10:14:00 +01:00
}
2022-11-07 12:10:56 +01:00
account . UpdatePeer ( peer )
2021-08-23 21:43:05 +02:00
2024-07-03 11:33:02 +02:00
err = am . Store . SaveAccount ( ctx , account )
2021-08-23 21:43:05 +02:00
if err != nil {
return nil , err
}
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2021-08-23 21:43:05 +02:00
2022-11-07 12:10:56 +01:00
return peer , nil
2021-08-23 21:43:05 +02:00
}
2023-10-01 19:51:39 +02:00
// deletePeers will delete all specified peers and send updates to the remote peers. Don't call without acquiring account lock
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) deletePeers ( ctx context . Context , account * Account , peerIDs [ ] string , userID string ) error {
2021-09-07 18:36:46 +02:00
2023-10-03 16:46:58 +02:00
// the first loop is needed to ensure all peers present under the account before modifying, otherwise
// we might have some inconsistencies
2023-11-28 13:45:26 +01:00
peers := make ( [ ] * nbpeer . Peer , 0 , len ( peerIDs ) )
2023-10-01 19:51:39 +02:00
for _ , peerID := range peerIDs {
2022-01-14 14:34:27 +01:00
2023-10-01 19:51:39 +02:00
peer := account . GetPeer ( peerID )
if peer == nil {
2023-10-03 16:46:58 +02:00
return status . Errorf ( status . NotFound , "peer %s not found" , peerID )
2023-10-01 19:51:39 +02:00
}
2023-10-03 16:46:58 +02:00
peers = append ( peers , peer )
}
2021-09-07 18:36:46 +02:00
2023-10-03 16:46:58 +02:00
// the 2nd loop performs the actual modification
for _ , peer := range peers {
2024-03-27 18:48:48 +01:00
2024-07-03 11:33:02 +02:00
err := am . integratedPeerValidator . PeerDeleted ( ctx , account . Id , peer . ID )
2024-03-27 18:48:48 +01:00
if err != nil {
return err
}
2023-10-03 16:46:58 +02:00
account . DeletePeer ( peer . ID )
2024-07-03 11:33:02 +02:00
am . peersUpdateManager . SendUpdate ( ctx , peer . ID ,
2023-10-01 19:51:39 +02:00
& UpdateMessage {
Update : & proto . SyncResponse {
// fill those field for backward compatibility
RemotePeers : [ ] * proto . RemotePeerConfig { } ,
RemotePeersIsEmpty : true ,
// new field
NetworkMap : & proto . NetworkMap {
Serial : account . Network . CurrentSerial ( ) ,
RemotePeers : [ ] * proto . RemotePeerConfig { } ,
RemotePeersIsEmpty : true ,
FirewallRules : [ ] * proto . FirewallRule { } ,
FirewallRulesIsEmpty : true ,
} ,
} ,
} )
2024-07-03 11:33:02 +02:00
am . peersUpdateManager . CloseChannel ( ctx , peer . ID )
am . StoreEvent ( ctx , userID , peer . ID , account . Id , activity . PeerRemovedByUser , peer . EventMeta ( am . GetDNSDomain ( ) ) )
2023-10-01 19:51:39 +02:00
}
2023-10-03 16:46:58 +02:00
return nil
2023-10-01 19:51:39 +02:00
}
// DeletePeer removes peer from the account by its IP
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) DeletePeer ( ctx context . Context , accountID , peerID , userID string ) error {
2024-07-31 14:53:32 +02:00
unlock := am . Store . AcquireWriteLockByUID ( ctx , accountID )
2023-10-01 19:51:39 +02:00
defer unlock ( )
2024-07-03 11:33:02 +02:00
account , err := am . Store . GetAccount ( ctx , accountID )
2023-10-01 19:51:39 +02:00
if err != nil {
return err
2021-09-07 18:36:46 +02:00
}
2024-07-03 11:33:02 +02:00
err = am . deletePeers ( ctx , account , [ ] string { peerID } , userID )
2023-10-03 16:46:58 +02:00
if err != nil {
return err
}
2024-07-03 11:33:02 +02:00
err = am . Store . SaveAccount ( ctx , account )
2023-10-03 16:46:58 +02:00
if err != nil {
return err
}
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2023-10-04 15:08:50 +02:00
return nil
2021-08-23 21:43:05 +02:00
}
2022-01-16 17:10:36 +01:00
// GetNetworkMap returns Network map for a given peer (omits original peer from the Peers result)
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) GetNetworkMap ( ctx context . Context , peerID string ) ( * NetworkMap , error ) {
account , err := am . Store . GetAccountByPeerID ( ctx , peerID )
2021-08-23 21:43:05 +02:00
if err != nil {
2022-11-11 20:36:45 +01:00
return nil , err
2021-08-23 21:43:05 +02:00
}
2023-02-03 10:33:28 +01:00
peer := account . GetPeer ( peerID )
if peer == nil {
return nil , status . Errorf ( status . NotFound , "peer with ID %s not found" , peerID )
}
2024-03-27 18:48:48 +01:00
groups := make ( map [ string ] [ ] string )
for groupID , group := range account . Groups {
groups [ groupID ] = group . Peers
}
validatedPeers , err := am . integratedPeerValidator . GetValidatedPeers ( account . Id , account . Groups , account . Peers , account . Settings . Extra )
if err != nil {
return nil , err
}
2024-08-07 10:52:31 +02:00
customZone := account . GetPeersCustomZone ( ctx , am . dnsDomain )
return account . GetPeerNetworkMap ( ctx , peer . ID , customZone , validatedPeers , nil ) , nil
2021-08-23 21:43:05 +02:00
}
2022-06-24 21:30:51 +02:00
// GetPeerNetwork returns the Network for a given peer
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) GetPeerNetwork ( ctx context . Context , peerID string ) ( * Network , error ) {
account , err := am . Store . GetAccountByPeerID ( ctx , peerID )
2022-06-24 21:30:51 +02:00
if err != nil {
2022-11-11 20:36:45 +01:00
return nil , err
2022-06-24 21:30:51 +02:00
}
return account . Network . Copy ( ) , err
}
2021-08-23 21:43:05 +02:00
// AddPeer adds a new peer to the Store.
2023-03-03 18:35:38 +01:00
// Each Account has a list of pre-authorized SetupKey and if no Account has a given key err with a code status.PermissionDenied
// will be returned, meaning the setup key is invalid or not found.
2022-05-05 20:02:15 +02:00
// If a User ID is provided, it means that we passed the authentication using JWT, then we look for account by User ID and register the peer
2023-03-03 18:35:38 +01:00
// to it. We also add the User ID to the peer metadata to identify registrant. If no userID provided, then fail with status.PermissionDenied
2021-08-23 21:43:05 +02:00
// 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).
2021-08-24 11:50:19 +02:00
// The peer property is just a placeholder for the Peer properties to pass further
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) AddPeer ( ctx context . Context , setupKey , userID string , peer * nbpeer . Peer ) ( * nbpeer . Peer , * NetworkMap , [ ] * posture . Checks , error ) {
2023-03-03 18:35:38 +01:00
if setupKey == "" && userID == "" {
// no auth method provided => reject access
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . Errorf ( status . Unauthenticated , "no peer auth method provided, please use a setup key or interactive SSO login" )
2023-03-03 18:35:38 +01:00
}
2021-08-23 21:43:05 +02:00
upperKey := strings . ToUpper ( setupKey )
2024-05-31 16:41:12 +02:00
var accountID string
2021-08-23 21:43:05 +02:00
var err error
2022-11-08 16:14:36 +01:00
addedByUser := false
if len ( userID ) > 0 {
addedByUser = true
2024-05-31 16:41:12 +02:00
accountID , err = am . Store . GetAccountIDByUserID ( userID )
2022-05-05 20:02:15 +02:00
} else {
2024-07-03 11:33:02 +02:00
accountID , err = am . Store . GetAccountIDBySetupKey ( ctx , setupKey )
2022-11-08 16:14:36 +01:00
}
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . Errorf ( status . NotFound , "failed adding new peer: account not found" )
2021-08-23 21:43:05 +02:00
}
2024-07-31 14:53:32 +02:00
unlock := am . Store . AcquireWriteLockByUID ( ctx , accountID )
2024-05-31 16:41:12 +02:00
defer func ( ) {
if unlock != nil {
unlock ( )
}
} ( )
2022-11-07 17:52:23 +01:00
2024-05-31 16:41:12 +02:00
var account * Account
2022-11-07 17:52:23 +01:00
// ensure that we consider modification happened meanwhile (because we were outside the account lock when we fetched the account)
2024-07-03 11:33:02 +02:00
account , err = am . Store . GetAccount ( ctx , accountID )
2022-11-07 17:52:23 +01:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-11-07 17:52:23 +01:00
}
2023-11-16 17:01:01 +01:00
if strings . ToLower ( peer . Meta . Hostname ) == "iphone" || strings . ToLower ( peer . Meta . Hostname ) == "ipad" && userID != "" {
2023-11-16 17:13:04 +01:00
if am . idpManager != nil {
2024-07-03 11:33:02 +02:00
userdata , err := am . lookupUserInCache ( ctx , userID , account )
2024-04-23 19:23:43 +02:00
if err == nil && userdata != nil {
2023-11-16 17:13:04 +01:00
peer . Meta . Hostname = fmt . Sprintf ( "%s-%s" , peer . Meta . Hostname , strings . Split ( userdata . Email , "@" ) [ 0 ] )
}
2023-11-16 16:46:08 +01:00
}
}
2023-06-02 18:04:24 +02:00
// This is a handling for the case when the same machine (with the same WireGuard pub key) tries to register twice.
2024-07-31 14:53:32 +02:00
// Such case is possible when AddPeer function takes long time to finish after AcquireWriteLockByUID (e.g., database is slow)
2023-06-02 18:04:24 +02:00
// and the peer disconnects with a timeout and tries to register again.
// We just check if this machine has been registered before and reject the second registration.
// The connecting peer should be able to recover with a retry.
2023-06-02 17:32:55 +02:00
_ , err = account . FindPeerByPubKey ( peer . Key )
if err == nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . Errorf ( status . PreconditionFailed , "peer has been already registered" )
2023-06-02 17:32:55 +02:00
}
2023-01-02 15:11:32 +01:00
opEvent := & activity . Event {
2023-04-03 15:09:35 +02:00
Timestamp : time . Now ( ) . UTC ( ) ,
2023-01-02 15:11:32 +01:00
AccountID : account . Id ,
}
2023-09-04 11:37:39 +02:00
var ephemeral bool
2023-12-04 13:49:46 +01:00
setupKeyName := ""
2022-11-08 16:14:36 +01:00
if ! addedByUser {
// validate the setup key if adding with a key
sk , err := account . FindSetupKey ( upperKey )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-11-08 16:14:36 +01:00
}
if ! sk . IsValid ( ) {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . Errorf ( status . PreconditionFailed , "couldn't add peer: setup key is invalid" )
2022-11-07 15:38:21 +01:00
}
2022-11-08 16:14:36 +01:00
account . SetupKeys [ sk . Key ] = sk . IncrementUsage ( )
2023-01-02 15:11:32 +01:00
opEvent . InitiatorID = sk . Id
opEvent . Activity = activity . PeerAddedWithSetupKey
2023-09-04 11:37:39 +02:00
ephemeral = sk . Ephemeral
2023-12-04 13:49:46 +01:00
setupKeyName = sk . Name
2023-01-02 15:11:32 +01:00
} else {
opEvent . InitiatorID = userID
opEvent . Activity = activity . PeerAddedByUser
2021-08-23 21:43:05 +02:00
}
2022-11-08 16:14:36 +01:00
takenIps := account . getTakenIPs ( )
existingLabels := account . getPeerDNSLabels ( )
2023-03-03 18:35:38 +01:00
newLabel , err := getPeerHostLabel ( peer . Meta . Hostname , existingLabels )
2022-11-07 15:38:21 +01:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-11-07 15:38:21 +01:00
}
peer . DNSLabel = newLabel
2021-08-23 21:43:05 +02:00
network := account . Network
2022-06-02 12:56:02 +02:00
nextIp , err := AllocatePeerIP ( network . Net , takenIps )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-06-02 12:56:02 +02:00
}
2021-08-23 21:43:05 +02:00
2024-03-02 13:49:40 +01:00
registrationTime := time . Now ( ) . UTC ( )
2023-11-28 13:45:26 +01:00
newPeer := & nbpeer . Peer {
2023-02-13 12:21:02 +01:00
ID : xid . New ( ) . String ( ) ,
Key : peer . Key ,
SetupKey : upperKey ,
IP : nextIp ,
Meta : peer . Meta ,
2023-03-03 18:35:38 +01:00
Name : peer . Meta . Hostname ,
2023-02-13 12:21:02 +01:00
DNSLabel : newLabel ,
UserID : userID ,
2024-03-02 13:49:40 +01:00
Status : & nbpeer . PeerStatus { Connected : false , LastSeen : registrationTime } ,
2023-02-13 12:21:02 +01:00
SSHEnabled : false ,
SSHKey : peer . SSHKey ,
2024-03-02 13:49:40 +01:00
LastLogin : registrationTime ,
CreatedAt : registrationTime ,
2023-03-23 17:47:53 +01:00
LoginExpirationEnabled : addedByUser ,
2023-09-04 11:37:39 +02:00
Ephemeral : ephemeral ,
2024-03-27 18:48:48 +01:00
Location : peer . Location ,
2023-12-04 16:26:34 +01:00
}
2023-11-28 11:44:08 +01:00
2024-07-29 13:30:27 +02:00
if am . geo != nil && newPeer . Location . ConnectionIP != nil {
location , err := am . geo . Lookup ( newPeer . Location . ConnectionIP )
if err != nil {
log . WithContext ( ctx ) . Warnf ( "failed to get location for new peer realip: [%s]: %v" , newPeer . Location . ConnectionIP . String ( ) , err )
} else {
newPeer . Location . CountryCode = location . Country . ISOCode
newPeer . Location . CityName = location . City . Names . En
newPeer . Location . GeoNameID = location . City . GeonameID
}
}
2022-05-21 15:21:39 +02:00
// add peer to 'All' group
group , err := account . GetGroupAll ( )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-05-21 15:21:39 +02:00
}
2023-12-04 16:26:34 +01:00
group . Peers = append ( group . Peers , newPeer . ID )
2022-05-21 15:21:39 +02:00
2022-11-08 16:14:36 +01:00
var groupsToAdd [ ] string
if addedByUser {
groupsToAdd , err = account . getUserGroups ( userID )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-11-08 16:14:36 +01:00
}
} else {
groupsToAdd , err = account . getSetupKeyGroups ( upperKey )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2022-11-08 16:14:36 +01:00
}
}
2022-09-13 13:39:46 +02:00
if len ( groupsToAdd ) > 0 {
for _ , s := range groupsToAdd {
if g , ok := account . Groups [ s ] ; ok && g . Name != "All" {
2023-12-04 16:26:34 +01:00
g . Peers = append ( g . Peers , newPeer . ID )
2022-09-13 13:39:46 +02:00
}
}
}
2024-07-03 11:33:02 +02:00
newPeer = am . integratedPeerValidator . PreparePeer ( ctx , account . Id , newPeer , account . GetPeerGroupsList ( newPeer . ID ) , account . Settings . Extra )
2024-03-27 18:48:48 +01:00
2024-01-06 12:57:05 +01:00
if addedByUser {
user , err := account . FindUser ( userID )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . Errorf ( status . Internal , "couldn't find user" )
2024-01-06 12:57:05 +01:00
}
user . updateLastLogin ( newPeer . LastLogin )
}
2023-12-04 16:26:34 +01:00
account . Peers [ newPeer . ID ] = newPeer
2022-01-14 14:34:27 +01:00
account . Network . IncSerial ( )
2024-07-03 11:33:02 +02:00
err = am . Store . SaveAccount ( ctx , account )
2021-08-23 21:43:05 +02:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2021-08-23 21:43:05 +02:00
}
2024-05-31 16:41:12 +02:00
// Account is saved, we can release the lock
unlock ( )
unlock = nil
2023-12-04 16:26:34 +01:00
opEvent . TargetID = newPeer . ID
opEvent . Meta = newPeer . EventMeta ( am . GetDNSDomain ( ) )
2023-12-04 13:49:46 +01:00
if ! addedByUser {
opEvent . Meta [ "setup_key_name" ] = setupKeyName
2023-12-04 13:00:13 +01:00
}
2023-12-04 12:49:36 +01:00
2024-07-03 11:33:02 +02:00
am . StoreEvent ( ctx , opEvent . InitiatorID , opEvent . TargetID , opEvent . AccountID , opEvent . Activity , opEvent . Meta )
2023-01-02 15:11:32 +01:00
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2023-03-03 18:35:38 +01:00
2024-03-27 18:48:48 +01:00
approvedPeersMap , err := am . GetValidatedPeers ( account )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-03-27 18:48:48 +01:00
}
2024-06-22 16:41:16 +02:00
postureChecks := am . getPeerPostureChecks ( account , peer )
2024-08-07 10:52:31 +02:00
customZone := account . GetPeersCustomZone ( ctx , am . dnsDomain )
networkMap := account . GetPeerNetworkMap ( ctx , newPeer . ID , customZone , approvedPeersMap , am . metrics . AccountManagerMetrics ( ) )
2024-06-22 16:41:16 +02:00
return newPeer , networkMap , postureChecks , nil
2021-08-23 21:43:05 +02:00
}
2022-05-23 13:03:57 +02:00
2023-03-03 18:35:38 +01:00
// SyncPeer checks whether peer is eligible for receiving NetworkMap (authenticated) and returns its NetworkMap if eligible
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) SyncPeer ( ctx context . Context , sync PeerSync , account * Account ) ( * nbpeer . Peer , * NetworkMap , [ ] * posture . Checks , error ) {
2023-03-03 18:35:38 +01:00
peer , err := account . FindPeerByPubKey ( sync . WireGuardPubKey )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . NewPeerNotRegisteredError ( )
2023-03-03 18:35:38 +01:00
}
2023-05-11 18:09:36 +02:00
err = checkIfPeerOwnerIsBlocked ( peer , account )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2023-05-11 18:09:36 +02:00
}
2024-07-03 11:33:02 +02:00
if peerLoginExpired ( ctx , peer , account . Settings ) {
2024-07-29 13:30:27 +02:00
return nil , nil , nil , status . NewPeerLoginExpiredError ( )
2023-02-13 12:21:02 +01:00
}
2024-03-27 18:48:48 +01:00
2024-06-13 13:24:24 +02:00
peer , updated := updatePeerMeta ( peer , sync . Meta , account )
if updated {
2024-07-26 07:49:05 +02:00
err = am . Store . SavePeer ( ctx , account . Id , peer )
2024-06-13 13:24:24 +02:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-06-13 13:24:24 +02:00
}
if sync . UpdateAccountPeers {
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2024-06-13 13:24:24 +02:00
}
}
2024-07-03 11:33:02 +02:00
peerNotValid , isStatusChanged , err := am . integratedPeerValidator . IsNotValidPeer ( ctx , account . Id , peer , account . GetPeerGroupsList ( peer . ID ) , account . Settings . Extra )
2024-05-24 13:29:25 +02:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-05-24 13:29:25 +02:00
}
2024-06-22 16:41:16 +02:00
var postureChecks [ ] * posture . Checks
2024-04-11 14:08:03 +02:00
if peerNotValid {
2024-03-27 18:48:48 +01:00
emptyMap := & NetworkMap {
Network : account . Network . Copy ( ) ,
}
2024-06-22 16:41:16 +02:00
return peer , emptyMap , postureChecks , nil
2024-03-27 18:48:48 +01:00
}
if isStatusChanged {
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2024-03-27 18:48:48 +01:00
}
2024-04-11 14:08:03 +02:00
validPeersMap , err := am . GetValidatedPeers ( account )
2024-03-27 18:48:48 +01:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-03-27 18:48:48 +01:00
}
2024-06-22 16:41:16 +02:00
postureChecks = am . getPeerPostureChecks ( account , peer )
2024-08-07 10:52:31 +02:00
customZone := account . GetPeersCustomZone ( ctx , am . dnsDomain )
return peer , account . GetPeerNetworkMap ( ctx , peer . ID , customZone , validPeersMap , am . metrics . AccountManagerMetrics ( ) ) , postureChecks , nil
2023-03-03 18:35:38 +01:00
}
// 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.
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) LoginPeer ( ctx context . Context , login PeerLogin ) ( * nbpeer . Peer , * NetworkMap , [ ] * posture . Checks , error ) {
accountID , err := am . Store . GetAccountIDByPeerPubKey ( ctx , login . WireGuardPubKey )
2023-03-03 18:35:38 +01:00
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.
2024-03-27 18:48:48 +01:00
newPeer := & nbpeer . Peer {
2024-07-29 13:30:27 +02:00
Key : login . WireGuardPubKey ,
Meta : login . Meta ,
SSHKey : login . SSHKey ,
Location : nbpeer . Location { ConnectionIP : login . ConnectionIP } ,
2024-03-27 18:48:48 +01:00
}
2024-07-03 11:33:02 +02:00
return am . AddPeer ( ctx , login . SetupKey , login . UserID , newPeer )
2023-03-03 18:35:38 +01:00
}
2024-06-22 16:41:16 +02:00
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Errorf ( "failed while logging in peer %s: %v" , login . WireGuardPubKey , err )
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . Errorf ( status . Internal , "failed while logging in peer" )
2023-03-03 18:35:38 +01:00
}
2024-07-29 13:30:27 +02:00
// when the client sends a login request with a JWT which is used to get the user ID,
// it means that the client has already checked if it needs login and had been through the SSO flow
// so, we can skip this check and directly proceed with the login
if login . UserID == "" {
err = am . checkIFPeerNeedsLoginWithoutLock ( ctx , accountID , login )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-05-31 16:41:12 +02:00
}
}
2024-07-31 14:53:32 +02:00
unlock := am . Store . AcquireWriteLockByUID ( ctx , accountID )
2024-05-31 16:41:12 +02:00
defer func ( ) {
if unlock != nil {
unlock ( )
}
} ( )
2023-03-03 18:35:38 +01:00
// fetch the account from the store once more after acquiring lock to avoid concurrent updates inconsistencies
2024-07-03 11:33:02 +02:00
account , err := am . Store . GetAccount ( ctx , accountID )
2023-03-03 18:35:38 +01:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2023-03-03 18:35:38 +01:00
}
2024-07-29 13:30:27 +02:00
peer , err := account . FindPeerByPubKey ( login . WireGuardPubKey )
2023-03-03 18:35:38 +01:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , status . NewPeerNotRegisteredError ( )
2023-03-03 18:35:38 +01:00
}
2023-05-11 18:09:36 +02:00
err = checkIfPeerOwnerIsBlocked ( peer , account )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2023-05-11 18:09:36 +02:00
}
2023-05-18 19:31:35 +02:00
// this flag prevents unnecessary calls to the persistent store.
2024-07-29 13:30:27 +02:00
shouldStorePeer := false
2023-03-10 17:39:29 +01:00
updateRemotePeers := false
2024-07-03 11:33:02 +02:00
if peerLoginExpired ( ctx , peer , account . Settings ) {
2024-07-29 13:30:27 +02:00
err = am . handleExpiredPeer ( ctx , login , account , peer )
2023-03-10 17:39:29 +01:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2023-03-10 17:39:29 +01:00
}
updateRemotePeers = true
2024-07-29 13:30:27 +02:00
shouldStorePeer = true
2023-03-03 18:35:38 +01:00
}
2024-07-03 11:33:02 +02:00
isRequiresApproval , isStatusChanged , err := am . integratedPeerValidator . IsNotValidPeer ( ctx , account . Id , peer , account . GetPeerGroupsList ( peer . ID ) , account . Settings . Extra )
2024-05-24 13:29:25 +02:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-05-24 13:29:25 +02:00
}
2024-07-29 13:30:27 +02:00
2023-05-18 19:31:35 +02:00
peer , updated := updatePeerMeta ( peer , login . Meta , account )
if updated {
2024-07-29 13:30:27 +02:00
shouldStorePeer = true
2023-05-18 19:31:35 +02:00
}
2023-03-03 18:35:38 +01:00
2024-07-29 13:30:27 +02:00
if peer . SSHKey != login . SSHKey {
peer . SSHKey = login . SSHKey
shouldStorePeer = true
2023-03-03 18:35:38 +01:00
}
2024-07-29 13:30:27 +02:00
if shouldStorePeer {
err = am . Store . SavePeer ( ctx , accountID , peer )
2023-05-18 19:31:35 +02:00
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2023-05-18 19:31:35 +02:00
}
2023-03-03 18:35:38 +01:00
}
2024-07-29 13:30:27 +02:00
2024-05-31 16:41:12 +02:00
unlock ( )
unlock = nil
2023-05-18 19:31:35 +02:00
2024-03-27 18:48:48 +01:00
if updateRemotePeers || isStatusChanged {
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2023-03-10 17:39:29 +01:00
}
2024-03-27 18:48:48 +01:00
2024-07-29 13:30:27 +02:00
return am . getValidatedPeerWithMap ( ctx , isRequiresApproval , account , peer )
}
// checkIFPeerNeedsLoginWithoutLock checks if the peer needs login without acquiring the account lock. The check validate if the peer was not added via SSO
// and if the peer login is expired.
// The NetBird client doesn't have a way to check if the peer needs login besides sending a login request
// with no JWT token and usually no setup-key. As the client can send up to two login request to check if it is expired
// and before starting the engine, we do the checks without an account lock to avoid piling up requests.
func ( am * DefaultAccountManager ) checkIFPeerNeedsLoginWithoutLock ( ctx context . Context , accountID string , login PeerLogin ) error {
peer , err := am . Store . GetPeerByPeerPubKey ( ctx , login . WireGuardPubKey )
if err != nil {
return err
}
// if the peer was not added with SSO login we can exit early because peers activated with setup-key
// doesn't expire, and we avoid extra databases calls.
if ! peer . AddedWithSSOLogin ( ) {
return nil
}
settings , err := am . Store . GetAccountSettings ( ctx , accountID )
if err != nil {
return err
}
if peerLoginExpired ( ctx , peer , settings ) {
return status . NewPeerLoginExpiredError ( )
}
return nil
}
func ( am * DefaultAccountManager ) getValidatedPeerWithMap ( ctx context . Context , isRequiresApproval bool , account * Account , peer * nbpeer . Peer ) ( * nbpeer . Peer , * NetworkMap , [ ] * posture . Checks , error ) {
2024-06-22 16:41:16 +02:00
var postureChecks [ ] * posture . Checks
2024-03-27 18:48:48 +01:00
if isRequiresApproval {
emptyMap := & NetworkMap {
Network : account . Network . Copy ( ) ,
}
2024-07-29 13:30:27 +02:00
return peer , emptyMap , nil , nil
2024-03-27 18:48:48 +01:00
}
approvedPeersMap , err := am . GetValidatedPeers ( account )
if err != nil {
2024-06-22 16:41:16 +02:00
return nil , nil , nil , err
2024-03-27 18:48:48 +01:00
}
2024-06-22 16:41:16 +02:00
postureChecks = am . getPeerPostureChecks ( account , peer )
2024-03-27 18:48:48 +01:00
2024-08-07 10:52:31 +02:00
customZone := account . GetPeersCustomZone ( ctx , am . dnsDomain )
return peer , account . GetPeerNetworkMap ( ctx , peer . ID , customZone , approvedPeersMap , am . metrics . AccountManagerMetrics ( ) ) , postureChecks , nil
2023-03-03 18:35:38 +01:00
}
2024-07-29 13:30:27 +02:00
func ( am * DefaultAccountManager ) handleExpiredPeer ( ctx context . Context , login PeerLogin , account * Account , peer * nbpeer . Peer ) error {
err := checkAuth ( ctx , login . UserID , peer )
if err != nil {
return err
}
// If peer was expired before and if it reached this point, it is re-authenticated.
// UserID is present, meaning that JWT validation passed successfully in the API layer.
updatePeerLastLogin ( peer , account )
// sync user last login with peer last login
user , err := account . FindUser ( login . UserID )
if err != nil {
return status . Errorf ( status . Internal , "couldn't find user" )
}
err = am . Store . SaveUserLastLogin ( account . Id , user . Id , peer . LastLogin )
if err != nil {
return err
}
am . StoreEvent ( ctx , login . UserID , peer . ID , account . Id , activity . UserLoggedInPeer , peer . EventMeta ( am . GetDNSDomain ( ) ) )
return nil
}
2023-11-28 13:45:26 +01:00
func checkIfPeerOwnerIsBlocked ( peer * nbpeer . Peer , account * Account ) error {
2023-05-11 18:09:36 +02:00
if peer . AddedWithSSOLogin ( ) {
user , err := account . FindUser ( peer . UserID )
if err != nil {
return status . Errorf ( status . PermissionDenied , "user doesn't exist" )
}
if user . IsBlocked ( ) {
return status . Errorf ( status . PermissionDenied , "user is blocked" )
}
}
return nil
}
2024-07-03 11:33:02 +02:00
func checkAuth ( ctx context . Context , loginUserID string , peer * nbpeer . Peer ) error {
2023-03-10 17:39:29 +01:00
if loginUserID == "" {
// absence of a user ID indicates that JWT wasn't provided.
2024-07-29 13:30:27 +02:00
return status . NewPeerLoginExpiredError ( )
2023-03-10 17:39:29 +01:00
}
if peer . UserID != loginUserID {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Warnf ( "user mismatch when logging in peer %s: peer user %s, login user %s " , peer . ID , peer . UserID , loginUserID )
2024-07-29 13:30:27 +02:00
return status . Errorf ( status . Unauthenticated , "can't login with this credentials" )
2023-03-10 17:39:29 +01:00
}
return nil
}
2024-07-03 11:33:02 +02:00
func peerLoginExpired ( ctx context . Context , peer * nbpeer . Peer , settings * Settings ) bool {
2024-05-31 16:41:12 +02:00
expired , expiresIn := peer . LoginExpired ( settings . PeerLoginExpiration )
expired = settings . PeerLoginExpirationEnabled && expired
2023-03-10 17:39:29 +01:00
if expired || peer . Status . LoginExpired {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Debugf ( "peer's %s login expired %v ago" , peer . ID , expiresIn )
2023-03-10 17:39:29 +01:00
return true
}
return false
}
2023-11-28 13:45:26 +01:00
func updatePeerLastLogin ( peer * nbpeer . Peer , account * Account ) {
2023-03-10 17:39:29 +01:00
peer . UpdateLastLogin ( )
2023-03-03 18:35:38 +01:00
account . UpdatePeer ( peer )
2023-03-10 17:39:29 +01:00
}
2022-06-23 17:04:53 +02:00
// UpdatePeerSSHKey updates peer's public SSH key
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) UpdatePeerSSHKey ( ctx context . Context , peerID string , sshKey string ) error {
2022-06-23 17:04:53 +02:00
if sshKey == "" {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Debugf ( "empty SSH key provided for peer %s, skipping update" , peerID )
2022-06-23 17:04:53 +02:00
return nil
}
2024-07-03 11:33:02 +02:00
account , err := am . Store . GetAccountByPeerID ( ctx , peerID )
2022-06-23 17:04:53 +02:00
if err != nil {
return err
}
2024-07-31 14:53:32 +02:00
unlock := am . Store . AcquireWriteLockByUID ( ctx , account . Id )
2022-11-07 17:52:23 +01:00
defer unlock ( )
// ensure that we consider modification happened meanwhile (because we were outside the account lock when we fetched the account)
2024-07-03 11:33:02 +02:00
account , err = am . Store . GetAccount ( ctx , account . Id )
2022-11-07 17:52:23 +01:00
if err != nil {
return err
}
2023-02-03 10:33:28 +01:00
peer := account . GetPeer ( peerID )
if peer == nil {
return status . Errorf ( status . NotFound , "peer with ID %s not found" , peerID )
2022-06-23 17:04:53 +02:00
}
2022-11-07 12:10:56 +01:00
if peer . SSHKey == sshKey {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Debugf ( "same SSH key provided for peer %s, skipping update" , peerID )
2022-11-07 12:10:56 +01:00
return nil
}
peer . SSHKey = sshKey
account . UpdatePeer ( peer )
2022-06-23 17:04:53 +02:00
2024-07-03 11:33:02 +02:00
err = am . Store . SaveAccount ( ctx , account )
2022-06-23 17:04:53 +02:00
if err != nil {
return err
}
// trigger network map update
2024-07-03 11:33:02 +02:00
am . updateAccountPeers ( ctx , account )
2023-10-04 15:08:50 +02:00
return nil
2022-06-23 17:04:53 +02:00
}
2023-02-07 20:11:08 +01:00
// GetPeer for a given accountID, peerID and userID error if not found.
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) GetPeer ( ctx context . Context , accountID , peerID , userID string ) ( * nbpeer . Peer , error ) {
2024-07-31 14:53:32 +02:00
unlock := am . Store . AcquireWriteLockByUID ( ctx , accountID )
2023-02-07 20:11:08 +01:00
defer unlock ( )
2024-07-03 11:33:02 +02:00
account , err := am . Store . GetAccount ( ctx , accountID )
2023-02-07 20:11:08 +01:00
if err != nil {
return nil , err
}
user , err := account . FindUser ( userID )
if err != nil {
return nil , err
}
2024-03-27 16:11:45 +01:00
if ! user . HasAdminPower ( ) && ! user . IsServiceUser && account . Settings . RegularUsersViewBlocked {
return nil , status . Errorf ( status . Internal , "user %s has no access to his own peer %s under account %s" , userID , peerID , accountID )
}
2023-02-07 20:11:08 +01:00
peer := account . GetPeer ( peerID )
if peer == nil {
return nil , status . Errorf ( status . NotFound , "peer with %s not found under account %s" , peerID , accountID )
}
// if admin or user owns this peer, return peer
2024-01-25 09:50:27 +01:00
if user . HasAdminPower ( ) || user . IsServiceUser || peer . UserID == userID {
2023-02-07 20:11:08 +01:00
return peer , nil
}
// it is also possible that user doesn't own the peer but some of his peers have access to it,
// this is a valid case, show the peer as well.
userPeers , err := account . FindUserPeers ( userID )
if err != nil {
return nil , err
}
2024-03-27 18:48:48 +01:00
approvedPeersMap , err := am . GetValidatedPeers ( account )
if err != nil {
return nil , err
}
2023-02-07 20:11:08 +01:00
for _ , p := range userPeers {
2024-07-03 11:33:02 +02:00
aclPeers , _ := account . getPeerConnectionResources ( ctx , p . ID , approvedPeersMap )
2023-02-07 20:11:08 +01:00
for _ , aclPeer := range aclPeers {
if aclPeer . ID == peerID {
return peer , nil
}
}
}
return nil , status . Errorf ( status . Internal , "user %s has no access to peer %s under account %s" , userID , peerID , accountID )
}
2023-11-28 13:45:26 +01:00
func updatePeerMeta ( peer * nbpeer . Peer , meta nbpeer . PeerSystemMeta , account * Account ) ( * nbpeer . Peer , bool ) {
2023-05-18 19:31:35 +02:00
if peer . UpdateMetaIfNew ( meta ) {
account . UpdatePeer ( peer )
return peer , true
}
return peer , false
2022-05-23 13:03:57 +02:00
}
2022-06-04 22:02:22 +02:00
2022-06-23 17:04:53 +02:00
// updateAccountPeers updates all peers that belong to an account.
// Should be called when changes have to be synced to peers.
2024-07-03 11:33:02 +02:00
func ( am * DefaultAccountManager ) updateAccountPeers ( ctx context . Context , account * Account ) {
2024-08-07 10:52:31 +02:00
start := time . Now ( )
defer func ( ) {
if am . metrics != nil {
am . metrics . AccountManagerMetrics ( ) . CountUpdateAccountPeersDuration ( time . Since ( start ) )
}
} ( )
2022-11-07 12:10:56 +01:00
peers := account . GetPeers ( )
2022-06-24 21:30:51 +02:00
2024-03-27 18:48:48 +01:00
approvedPeersMap , err := am . GetValidatedPeers ( account )
if err != nil {
2024-08-07 10:52:31 +02:00
log . WithContext ( ctx ) . Errorf ( "failed to send out updates to peers, failed to validate peer: %v" , err )
2024-03-27 18:48:48 +01:00
return
}
2024-08-07 10:52:31 +02:00
var wg sync . WaitGroup
semaphore := make ( chan struct { } , 10 )
dnsCache := & DNSConfigCache { }
customZone := account . GetPeersCustomZone ( ctx , am . dnsDomain )
2022-08-18 18:22:15 +02:00
for _ , peer := range peers {
2024-04-29 18:31:52 +02:00
if ! am . peersUpdateManager . HasChannel ( peer . ID ) {
2024-07-03 11:33:02 +02:00
log . WithContext ( ctx ) . Tracef ( "peer %s doesn't have a channel, skipping network map update" , peer . ID )
2024-04-29 18:31:52 +02:00
continue
}
2024-06-22 16:41:16 +02:00
2024-08-07 10:52:31 +02:00
wg . Add ( 1 )
semaphore <- struct { } { }
go func ( p * nbpeer . Peer ) {
defer wg . Done ( )
defer func ( ) { <- semaphore } ( )
postureChecks := am . getPeerPostureChecks ( account , p )
remotePeerNetworkMap := account . GetPeerNetworkMap ( ctx , p . ID , customZone , approvedPeersMap , am . metrics . AccountManagerMetrics ( ) )
update := toSyncResponse ( ctx , nil , p , nil , remotePeerNetworkMap , am . GetDNSDomain ( ) , postureChecks , dnsCache )
am . peersUpdateManager . SendUpdate ( ctx , p . ID , & UpdateMessage { Update : update } )
} ( peer )
2022-06-04 22:02:22 +02:00
}
2024-08-07 10:52:31 +02:00
wg . Wait ( )
2022-06-04 22:02:22 +02:00
}