mirror of
https://github.com/netbirdio/netbird.git
synced 2026-06-19 14:29:55 +00:00
Compare commits
5 Commits
fix/browse
...
feature/me
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
799a7f1b57 | ||
|
|
55177dae77 | ||
|
|
02958887bc | ||
|
|
10bb6cc700 | ||
|
|
99505b6bb2 |
@@ -298,6 +298,10 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
||||
c.clientMetrics.RecordLoginDuration(engineCtx, time.Since(loginStarted), true)
|
||||
c.statusRecorder.MarkManagementConnected()
|
||||
|
||||
if metricsConfig := loginResp.GetNetbirdConfig().GetMetrics(); metricsConfig != nil {
|
||||
c.clientMetrics.UpdatePushFromMgm(c.ctx, metricsConfig.GetEnabled())
|
||||
}
|
||||
|
||||
localPeerState := peer.LocalPeerState{
|
||||
IP: loginResp.GetPeerConfig().GetAddress(),
|
||||
PubKey: myPrivateKey.PublicKey().String(),
|
||||
|
||||
@@ -942,6 +942,8 @@ func (e *Engine) updateNetbirdConfig(wCfg *mgmProto.NetbirdConfig) error {
|
||||
return fmt.Errorf("handle the flow configuration: %w", err)
|
||||
}
|
||||
|
||||
e.handleMetricsUpdate(wCfg.GetMetrics())
|
||||
|
||||
if err := e.PopulateNetbirdConfig(wCfg, nil); err != nil {
|
||||
log.Warnf("Failed to update DNS server config: %v", err)
|
||||
}
|
||||
@@ -1011,6 +1013,14 @@ func (e *Engine) handleFlowUpdate(config *mgmProto.FlowConfig) error {
|
||||
return e.flowManager.Update(flowConfig)
|
||||
}
|
||||
|
||||
func (e *Engine) handleMetricsUpdate(config *mgmProto.MetricsConfig) {
|
||||
if config == nil {
|
||||
return
|
||||
}
|
||||
log.Infof("received metrics configuration from management: enabled=%v", config.GetEnabled())
|
||||
e.clientMetrics.UpdatePushFromMgm(e.ctx, config.GetEnabled())
|
||||
}
|
||||
|
||||
func toFlowLoggerConfig(config *mgmProto.FlowConfig) (*nftypes.FlowConfig, error) {
|
||||
if config.GetInterval() == nil {
|
||||
return nil, errors.New("flow interval is nil")
|
||||
|
||||
@@ -60,6 +60,13 @@ func getMetricsInterval() time.Duration {
|
||||
return interval
|
||||
}
|
||||
|
||||
// isMetricsPushEnvSet returns true if NB_METRICS_PUSH_ENABLED is explicitly set (to any value).
|
||||
// When set, the env var takes full precedence over management server configuration.
|
||||
func isMetricsPushEnvSet() bool {
|
||||
_, set := os.LookupEnv(EnvMetricsPushEnabled)
|
||||
return set
|
||||
}
|
||||
|
||||
func isForceSending() bool {
|
||||
force, _ := strconv.ParseBool(os.Getenv(EnvMetricsForceSending))
|
||||
return force
|
||||
|
||||
@@ -169,7 +169,7 @@ func (c *ClientMetrics) Export(w io.Writer) error {
|
||||
return c.impl.Export(w)
|
||||
}
|
||||
|
||||
// StartPush starts periodic pushing of metrics with the given configuration
|
||||
// StartPush starts periodic pushing of metrics with the given configuration.
|
||||
// Precedence: PushConfig.ServerAddress > remote config server_url
|
||||
func (c *ClientMetrics) StartPush(ctx context.Context, config PushConfig) {
|
||||
if c == nil {
|
||||
@@ -184,6 +184,53 @@ func (c *ClientMetrics) StartPush(ctx context.Context, config PushConfig) {
|
||||
return
|
||||
}
|
||||
|
||||
c.startPushLocked(ctx, config)
|
||||
}
|
||||
|
||||
// StopPush stops the periodic metrics push.
|
||||
func (c *ClientMetrics) StopPush() {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
c.pushMu.Lock()
|
||||
defer c.pushMu.Unlock()
|
||||
|
||||
c.stopPushLocked()
|
||||
}
|
||||
|
||||
// UpdatePushFromMgm updates metrics push based on management server configuration.
|
||||
// If NB_METRICS_PUSH_ENABLED is explicitly set (true or false), management config is ignored.
|
||||
// When unset, management controls whether push is enabled.
|
||||
func (c *ClientMetrics) UpdatePushFromMgm(ctx context.Context, enabled bool) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if isMetricsPushEnvSet() {
|
||||
log.Debugf("ignoring management config, env var is explicitly set: %s", EnvMetricsPushEnabled)
|
||||
return
|
||||
}
|
||||
|
||||
c.pushMu.Lock()
|
||||
defer c.pushMu.Unlock()
|
||||
|
||||
if enabled {
|
||||
if c.push != nil {
|
||||
return
|
||||
}
|
||||
log.Infof("enabled metrics push by management")
|
||||
c.startPushLocked(ctx, PushConfigFromEnv())
|
||||
} else {
|
||||
if c.push == nil {
|
||||
return
|
||||
}
|
||||
log.Infof("disabled metrics push by management")
|
||||
c.stopPushLocked()
|
||||
}
|
||||
}
|
||||
|
||||
// startPushLocked starts push. Caller must hold pushMu.
|
||||
func (c *ClientMetrics) startPushLocked(ctx context.Context, config PushConfig) {
|
||||
c.mu.RLock()
|
||||
agentVersion := c.agentInfo.Version
|
||||
peerID := c.agentInfo.peerID
|
||||
@@ -208,12 +255,8 @@ func (c *ClientMetrics) StartPush(ctx context.Context, config PushConfig) {
|
||||
c.push = push
|
||||
}
|
||||
|
||||
func (c *ClientMetrics) StopPush() {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
c.pushMu.Lock()
|
||||
defer c.pushMu.Unlock()
|
||||
// stopPushLocked stops push. Caller must hold pushMu.
|
||||
func (c *ClientMetrics) stopPushLocked() {
|
||||
if c.push == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -585,66 +585,66 @@ func (b *bufferAffectedUpdate) setTimer(d time.Duration, f func()) {
|
||||
b.next.Reset(d)
|
||||
}
|
||||
|
||||
func (c *Controller) GetValidatedPeerWithMap(ctx context.Context, isRequiresApproval bool, accountID string, peerID string) (*types.NetworkMap, []*posture.Checks, int64, error) {
|
||||
func (c *Controller) GetValidatedPeerWithMap(ctx context.Context, isRequiresApproval bool, accountID string, peer *nbpeer.Peer) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, int64, error) {
|
||||
if isRequiresApproval {
|
||||
network, err := c.repo.GetAccountNetwork(ctx, accountID)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
emptyMap := &types.NetworkMap{
|
||||
Network: network.Copy(),
|
||||
}
|
||||
return emptyMap, nil, 0, nil
|
||||
return peer, emptyMap, nil, 0, nil
|
||||
}
|
||||
|
||||
account, err := c.requestBuffer.GetAccountWithBackpressure(ctx, accountID)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
account.InjectProxyPolicies(ctx)
|
||||
|
||||
approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
startPosture := time.Now()
|
||||
postureChecks, err := c.getPeerPostureChecks(account, peerID)
|
||||
postureChecks, err := c.getPeerPostureChecks(account, peer.ID)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
log.WithContext(ctx).Debugf("getPeerPostureChecks took %s", time.Since(startPosture))
|
||||
|
||||
accountZones, err := c.repo.GetAccountZones(ctx, account.Id)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to get account zones: %v", err)
|
||||
return nil, nil, 0, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
dnsDomain := c.GetDNSDomain(account.Settings)
|
||||
peersCustomZone := account.GetPeersCustomZone(ctx, dnsDomain)
|
||||
|
||||
proxyNetworkMaps, err := c.proxyController.GetProxyNetworkMaps(ctx, account.Id, peerID, account.Peers)
|
||||
proxyNetworkMaps, err := c.proxyController.GetProxyNetworkMaps(ctx, account.Id, peer.ID, account.Peers)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to get proxy network maps: %v", err)
|
||||
return nil, nil, 0, err
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
networkMap := account.GetPeerNetworkMapFromComponents(ctx, peerID, peersCustomZone, accountZones, approvedPeersMap, resourcePolicies, routers, c.accountManagerMetrics, groupIDToUserIDs)
|
||||
networkMap := account.GetPeerNetworkMapFromComponents(ctx, peer.ID, peersCustomZone, accountZones, approvedPeersMap, resourcePolicies, routers, c.accountManagerMetrics, groupIDToUserIDs)
|
||||
|
||||
proxyNetworkMap, ok := proxyNetworkMaps[peerID]
|
||||
proxyNetworkMap, ok := proxyNetworkMaps[peer.ID]
|
||||
if ok {
|
||||
networkMap.Merge(proxyNetworkMap)
|
||||
}
|
||||
|
||||
dnsFwdPort := computeForwarderPort(maps.Values(account.Peers), network_map.DnsForwarderPortMinVersion)
|
||||
|
||||
return networkMap, postureChecks, dnsFwdPort, nil
|
||||
return peer, networkMap, postureChecks, dnsFwdPort, nil
|
||||
}
|
||||
|
||||
// GetDNSDomain returns the configured dnsDomain
|
||||
|
||||
@@ -23,7 +23,7 @@ type Controller interface {
|
||||
BufferUpdateAffectedPeers(ctx context.Context, accountID string, peerIDs []string, reason types.UpdateReason) error
|
||||
UpdateAccountPeer(ctx context.Context, accountId string, peerId string) error
|
||||
BufferUpdateAccountPeers(ctx context.Context, accountID string, reason types.UpdateReason) error
|
||||
GetValidatedPeerWithMap(ctx context.Context, isRequiresApproval bool, accountID string, peerID string) (*types.NetworkMap, []*posture.Checks, int64, error)
|
||||
GetValidatedPeerWithMap(ctx context.Context, isRequiresApproval bool, accountID string, p *nbpeer.Peer) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, int64, error)
|
||||
GetDNSDomain(settings *types.Settings) string
|
||||
StartWarmup(context.Context)
|
||||
GetNetworkMap(ctx context.Context, peerID string) (*types.NetworkMap, error)
|
||||
|
||||
@@ -127,20 +127,21 @@ func (mr *MockControllerMockRecorder) GetNetworkMap(ctx, peerID any) *gomock.Cal
|
||||
}
|
||||
|
||||
// GetValidatedPeerWithMap mocks base method.
|
||||
func (m *MockController) GetValidatedPeerWithMap(ctx context.Context, isRequiresApproval bool, accountID string, peerID string) (*types.NetworkMap, []*posture.Checks, int64, error) {
|
||||
func (m *MockController) GetValidatedPeerWithMap(ctx context.Context, isRequiresApproval bool, accountID string, p *peer.Peer) (*peer.Peer, *types.NetworkMap, []*posture.Checks, int64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetValidatedPeerWithMap", ctx, isRequiresApproval, accountID, peerID)
|
||||
ret0, _ := ret[0].(*types.NetworkMap)
|
||||
ret1, _ := ret[1].([]*posture.Checks)
|
||||
ret2, _ := ret[2].(int64)
|
||||
ret3, _ := ret[3].(error)
|
||||
return ret0, ret1, ret2, ret3
|
||||
ret := m.ctrl.Call(m, "GetValidatedPeerWithMap", ctx, isRequiresApproval, accountID, p)
|
||||
ret0, _ := ret[0].(*peer.Peer)
|
||||
ret1, _ := ret[1].(*types.NetworkMap)
|
||||
ret2, _ := ret[2].([]*posture.Checks)
|
||||
ret3, _ := ret[3].(int64)
|
||||
ret4, _ := ret[4].(error)
|
||||
return ret0, ret1, ret2, ret3, ret4
|
||||
}
|
||||
|
||||
// GetValidatedPeerWithMap indicates an expected call of GetValidatedPeerWithMap.
|
||||
func (mr *MockControllerMockRecorder) GetValidatedPeerWithMap(ctx, isRequiresApproval, accountID, peerID any) *gomock.Call {
|
||||
func (mr *MockControllerMockRecorder) GetValidatedPeerWithMap(ctx, isRequiresApproval, accountID, p any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatedPeerWithMap", reflect.TypeOf((*MockController)(nil).GetValidatedPeerWithMap), ctx, isRequiresApproval, accountID, peerID)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatedPeerWithMap", reflect.TypeOf((*MockController)(nil).GetValidatedPeerWithMap), ctx, isRequiresApproval, accountID, p)
|
||||
}
|
||||
|
||||
// OnPeerConnected mocks base method.
|
||||
|
||||
@@ -242,7 +242,7 @@ func (m *managerImpl) CreateProxyPeer(ctx context.Context, accountID string, pee
|
||||
},
|
||||
}
|
||||
|
||||
_, _, _, _, err = m.accountManager.AddPeer(ctx, accountID, "", "", peer, true)
|
||||
_, _, _, err = m.accountManager.AddPeer(ctx, accountID, "", "", peer, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create proxy peer: %w", err)
|
||||
}
|
||||
|
||||
@@ -47,9 +47,16 @@ func init() {
|
||||
precomputedDeprecatedRemotePeersConstraint = constraint
|
||||
}
|
||||
|
||||
func toNetbirdConfig(config *nbconfig.Config, turnCredentials *Token, relayToken *Token, extraSettings *types.ExtraSettings) *proto.NetbirdConfig {
|
||||
func toNetbirdConfig(config *nbconfig.Config, turnCredentials *Token, relayToken *Token, extraSettings *types.ExtraSettings, settings *types.Settings) *proto.NetbirdConfig {
|
||||
if config == nil {
|
||||
return nil
|
||||
if settings == nil {
|
||||
return nil
|
||||
}
|
||||
return &proto.NetbirdConfig{
|
||||
Metrics: &proto.MetricsConfig{
|
||||
Enabled: settings.MetricsPushEnabled,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var stuns []*proto.HostConfig
|
||||
@@ -110,6 +117,12 @@ func toNetbirdConfig(config *nbconfig.Config, turnCredentials *Token, relayToken
|
||||
Relay: relayCfg,
|
||||
}
|
||||
|
||||
if settings != nil {
|
||||
nbConfig.Metrics = &proto.MetricsConfig{
|
||||
Enabled: settings.MetricsPushEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
return nbConfig
|
||||
}
|
||||
|
||||
@@ -166,7 +179,7 @@ func ToSyncResponse(ctx context.Context, config *nbconfig.Config, httpConfig *nb
|
||||
Checks: toProtocolChecks(ctx, checks),
|
||||
}
|
||||
|
||||
nbConfig := toNetbirdConfig(config, turnCredentials, relayCredentials, extraSettings)
|
||||
nbConfig := toNetbirdConfig(config, turnCredentials, relayCredentials, extraSettings, settings)
|
||||
extendedConfig := integrationsConfig.ExtendNetBirdConfig(peer.ID, peerGroups, nbConfig, extraSettings)
|
||||
response.NetbirdConfig = extendedConfig
|
||||
|
||||
|
||||
@@ -778,7 +778,7 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
|
||||
sshKey = loginReq.GetPeerKeys().GetSshPubKey()
|
||||
}
|
||||
|
||||
peer, network, postureChecks, enableSSH, err := s.accountManager.LoginPeer(ctx, types.PeerLogin{
|
||||
peer, netMap, postureChecks, err := s.accountManager.LoginPeer(ctx, types.PeerLogin{
|
||||
WireGuardPubKey: peerKey.String(),
|
||||
SSHKey: string(sshKey),
|
||||
Meta: peerMeta,
|
||||
@@ -792,7 +792,7 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
|
||||
return nil, mapError(ctx, err)
|
||||
}
|
||||
|
||||
loginResp, err := s.prepareLoginResponse(ctx, peer, network, postureChecks, enableSSH)
|
||||
loginResp, err := s.prepareLoginResponse(ctx, peer, netMap, postureChecks)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Warnf("failed preparing login response for peer %s: %s", peerKey, err)
|
||||
return nil, status.Errorf(codes.Internal, "failed logging in peer")
|
||||
@@ -895,7 +895,7 @@ func (s *Server) ExtendAuthSession(ctx context.Context, req *proto.EncryptedMess
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) prepareLoginResponse(ctx context.Context, peer *nbpeer.Peer, network *types.Network, postureChecks []*posture.Checks, enableSSH bool) (*proto.LoginResponse, error) {
|
||||
func (s *Server) prepareLoginResponse(ctx context.Context, peer *nbpeer.Peer, netMap *types.NetworkMap, postureChecks []*posture.Checks) (*proto.LoginResponse, error) {
|
||||
var relayToken *Token
|
||||
var err error
|
||||
if s.config.Relay != nil && len(s.config.Relay.Addresses) > 0 {
|
||||
@@ -913,8 +913,8 @@ func (s *Server) prepareLoginResponse(ctx context.Context, peer *nbpeer.Peer, ne
|
||||
|
||||
// if peer has reached this point then it has logged in
|
||||
loginResp := &proto.LoginResponse{
|
||||
NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken, nil),
|
||||
PeerConfig: toPeerConfig(peer, network, s.networkMapController.GetDNSDomain(settings), settings, s.config.HttpConfig, s.config.DeviceAuthorizationFlow, enableSSH),
|
||||
NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken, nil, settings),
|
||||
PeerConfig: toPeerConfig(peer, netMap.Network, s.networkMapController.GetDNSDomain(settings), settings, s.config.HttpConfig, s.config.DeviceAuthorizationFlow, netMap.EnableSSH),
|
||||
Checks: toProtocolChecks(ctx, postureChecks),
|
||||
}
|
||||
|
||||
|
||||
@@ -357,6 +357,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
|
||||
oldSettings.DNSDomain != newSettings.DNSDomain ||
|
||||
oldSettings.AutoUpdateVersion != newSettings.AutoUpdateVersion ||
|
||||
oldSettings.AutoUpdateAlways != newSettings.AutoUpdateAlways ||
|
||||
oldSettings.MetricsPushEnabled != newSettings.MetricsPushEnabled ||
|
||||
oldSettings.PeerLoginExpirationEnabled != newSettings.PeerLoginExpirationEnabled ||
|
||||
oldSettings.PeerLoginExpiration != newSettings.PeerLoginExpiration {
|
||||
// Session deadline is derived from LastLogin + PeerLoginExpiration
|
||||
@@ -409,6 +410,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
|
||||
am.handleAutoUpdateVersionSettings(ctx, oldSettings, newSettings, userID, accountID)
|
||||
am.handleAutoUpdateAlwaysSettings(ctx, oldSettings, newSettings, userID, accountID)
|
||||
am.handlePeerExposeSettings(ctx, oldSettings, newSettings, userID, accountID)
|
||||
am.handleMetricsPushSettings(ctx, oldSettings, newSettings, userID, accountID)
|
||||
if err = am.handleInactivityExpirationSettings(ctx, oldSettings, newSettings, userID, accountID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -563,6 +565,16 @@ func (am *DefaultAccountManager) handleLazyConnectionSettings(ctx context.Contex
|
||||
}
|
||||
}
|
||||
|
||||
func (am *DefaultAccountManager) handleMetricsPushSettings(ctx context.Context, oldSettings, newSettings *types.Settings, userID, accountID string) {
|
||||
if oldSettings.MetricsPushEnabled != newSettings.MetricsPushEnabled {
|
||||
if newSettings.MetricsPushEnabled {
|
||||
am.StoreEvent(ctx, userID, accountID, accountID, activity.AccountMetricsPushEnabled, nil)
|
||||
} else {
|
||||
am.StoreEvent(ctx, userID, accountID, accountID, activity.AccountMetricsPushDisabled, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (am *DefaultAccountManager) handlePeerLoginExpirationSettings(ctx context.Context, oldSettings, newSettings *types.Settings, userID, accountID string) {
|
||||
if oldSettings.PeerLoginExpirationEnabled != newSettings.PeerLoginExpirationEnabled {
|
||||
event := activity.AccountPeerLoginExpirationEnabled
|
||||
|
||||
@@ -70,7 +70,7 @@ type Manager interface {
|
||||
UpdatePeerIPv6(ctx context.Context, accountID, userID, peerID string, newIPv6 netip.Addr) error
|
||||
GetNetworkMap(ctx context.Context, peerID string) (*types.NetworkMap, error)
|
||||
GetPeerNetwork(ctx context.Context, peerID string) (*types.Network, error)
|
||||
AddPeer(ctx context.Context, accountID, setupKey, userID string, p *nbpeer.Peer, temporary bool) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error)
|
||||
AddPeer(ctx context.Context, accountID, setupKey, userID string, p *nbpeer.Peer, temporary bool) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error)
|
||||
CreatePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*types.PersonalAccessTokenGenerated, error)
|
||||
DeletePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) error
|
||||
GetPAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) (*types.PersonalAccessToken, error)
|
||||
@@ -109,7 +109,7 @@ type Manager interface {
|
||||
GetPeer(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error)
|
||||
UpdateAccountSettings(ctx context.Context, accountID, userID string, newSettings *types.Settings) (*types.Settings, error)
|
||||
UpdateAccountOnboarding(ctx context.Context, accountID, userID string, newOnboarding *types.AccountOnboarding) (*types.AccountOnboarding, error)
|
||||
LoginPeer(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error) // used by peer gRPC API
|
||||
LoginPeer(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) // used by peer gRPC API
|
||||
ExtendPeerSession(ctx context.Context, peerPubKey, userID string) (time.Time, error) // used by peer gRPC API for ExtendAuthSession
|
||||
SyncPeer(ctx context.Context, sync types.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, int64, error) // used by peer gRPC API
|
||||
GetExternalCacheManager() ExternalCacheManager
|
||||
|
||||
@@ -80,15 +80,14 @@ func (mr *MockManagerMockRecorder) AccountExists(ctx, accountID interface{}) *go
|
||||
}
|
||||
|
||||
// AddPeer mocks base method.
|
||||
func (m *MockManager) AddPeer(ctx context.Context, accountID, setupKey, userID string, p *peer.Peer, temporary bool) (*peer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
func (m *MockManager) AddPeer(ctx context.Context, accountID, setupKey, userID string, p *peer.Peer, temporary bool) (*peer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddPeer", ctx, accountID, setupKey, userID, p, temporary)
|
||||
ret0, _ := ret[0].(*peer.Peer)
|
||||
ret1, _ := ret[1].(*types.Network)
|
||||
ret1, _ := ret[1].(*types.NetworkMap)
|
||||
ret2, _ := ret[2].([]*posture.Checks)
|
||||
ret3, _ := ret[3].(bool)
|
||||
ret4, _ := ret[4].(error)
|
||||
return ret0, ret1, ret2, ret3, ret4
|
||||
ret3, _ := ret[3].(error)
|
||||
return ret0, ret1, ret2, ret3
|
||||
}
|
||||
|
||||
// AddPeer indicates an expected call of AddPeer.
|
||||
@@ -1290,15 +1289,14 @@ func (mr *MockManagerMockRecorder) ListUsers(ctx, accountID interface{}) *gomock
|
||||
}
|
||||
|
||||
// LoginPeer mocks base method.
|
||||
func (m *MockManager) LoginPeer(ctx context.Context, login types.PeerLogin) (*peer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
func (m *MockManager) LoginPeer(ctx context.Context, login types.PeerLogin) (*peer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LoginPeer", ctx, login)
|
||||
ret0, _ := ret[0].(*peer.Peer)
|
||||
ret1, _ := ret[1].(*types.Network)
|
||||
ret1, _ := ret[1].(*types.NetworkMap)
|
||||
ret2, _ := ret[2].([]*posture.Checks)
|
||||
ret3, _ := ret[3].(bool)
|
||||
ret4, _ := ret[4].(error)
|
||||
return ret0, ret1, ret2, ret3, ret4
|
||||
ret3, _ := ret[3].(error)
|
||||
return ret0, ret1, ret2, ret3
|
||||
}
|
||||
|
||||
// LoginPeer indicates an expected call of LoginPeer.
|
||||
|
||||
@@ -84,7 +84,7 @@ func verifyCanAddPeerToAccount(t *testing.T, manager nbAccount.Manager, account
|
||||
setupKey = key.Key
|
||||
}
|
||||
|
||||
_, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey, userID, peer, false)
|
||||
_, _, _, err := manager.AddPeer(context.Background(), "", setupKey, userID, peer, false)
|
||||
if err != nil {
|
||||
t.Error("expected to add new peer successfully after creating new account, but failed", err)
|
||||
}
|
||||
@@ -1092,7 +1092,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
||||
}
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
|
||||
peer, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
}, false)
|
||||
@@ -1156,7 +1156,7 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
expectedUserID := userID
|
||||
|
||||
peer, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
}, false)
|
||||
@@ -1504,7 +1504,7 @@ func TestAccountManager_DeletePeer(t *testing.T) {
|
||||
|
||||
peerKey := key.PublicKey().String()
|
||||
|
||||
peer, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: peerKey},
|
||||
}, false)
|
||||
@@ -1826,7 +1826,7 @@ func TestDefaultAccountManager_UpdatePeer_PeerLoginExpiration(t *testing.T) {
|
||||
|
||||
key, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err, "unable to generate WireGuard key")
|
||||
peer, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"},
|
||||
LoginExpirationEnabled: true,
|
||||
@@ -1882,7 +1882,7 @@ func TestDefaultAccountManager_MarkPeerConnected_PeerLoginExpiration(t *testing.
|
||||
|
||||
key, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err, "unable to generate WireGuard key")
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"},
|
||||
LoginExpirationEnabled: true,
|
||||
@@ -1927,7 +1927,7 @@ func TestDefaultAccountManager_OnPeerDisconnected_LastSeenCheck(t *testing.T) {
|
||||
require.NoError(t, err, "unable to generate WireGuard key")
|
||||
peerPubKey := key.PublicKey().String()
|
||||
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: peerPubKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"},
|
||||
}, false)
|
||||
@@ -2017,7 +2017,7 @@ func TestDefaultAccountManager_MarkPeerConnected_ConcurrentRace(t *testing.T) {
|
||||
require.NoError(t, err, "unable to generate WireGuard key")
|
||||
peerPubKey := key.PublicKey().String()
|
||||
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: peerPubKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "race-peer"},
|
||||
}, false)
|
||||
@@ -2080,7 +2080,7 @@ func TestDefaultAccountManager_UpdateAccountSettings_PeerLoginExpiration(t *test
|
||||
|
||||
key, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err, "unable to generate WireGuard key")
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer"},
|
||||
LoginExpirationEnabled: true,
|
||||
@@ -3276,7 +3276,7 @@ func setupNetworkMapTest(t *testing.T) (*DefaultAccountManager, *update_channel.
|
||||
}
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
|
||||
peer, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
Status: &nbpeer.PeerStatus{
|
||||
@@ -3444,7 +3444,7 @@ func BenchmarkLoginPeer_ExistingPeer(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
start := time.Now()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _, _, err := manager.LoginPeer(context.Background(), types.PeerLogin{
|
||||
_, _, _, err := manager.LoginPeer(context.Background(), types.PeerLogin{
|
||||
WireGuardPubKey: account.Peers["peer-1"].Key,
|
||||
SSHKey: "someKey",
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: strconv.Itoa(i)},
|
||||
@@ -3513,7 +3513,7 @@ func BenchmarkLoginPeer_NewPeer(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
start := time.Now()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, _, _, err := manager.LoginPeer(context.Background(), types.PeerLogin{
|
||||
_, _, _, err := manager.LoginPeer(context.Background(), types.PeerLogin{
|
||||
WireGuardPubKey: "some-new-key" + strconv.Itoa(i),
|
||||
SSHKey: "someKey",
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: strconv.Itoa(i)},
|
||||
@@ -3908,13 +3908,13 @@ func TestDefaultAccountManager_UpdatePeerIP(t *testing.T) {
|
||||
key2, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err, "unable to generate WireGuard key")
|
||||
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"},
|
||||
}, false)
|
||||
require.NoError(t, err, "unable to add peer1")
|
||||
|
||||
peer2, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
|
||||
@@ -225,6 +225,11 @@ const (
|
||||
// AccountAutoUpdateAlwaysDisabled indicates that a user disabled always auto-update for the account
|
||||
AccountAutoUpdateAlwaysDisabled Activity = 117
|
||||
|
||||
// AccountMetricsPushEnabled indicates that a user enabled metrics push for the account
|
||||
AccountMetricsPushEnabled Activity = 126
|
||||
// AccountMetricsPushDisabled indicates that a user disabled metrics push for the account
|
||||
AccountMetricsPushDisabled Activity = 127
|
||||
|
||||
// DomainAdded indicates that a user added a custom domain
|
||||
DomainAdded Activity = 118
|
||||
// DomainDeleted indicates that a user deleted a custom domain
|
||||
@@ -395,6 +400,9 @@ var activityMap = map[Activity]Code{
|
||||
AccountPeerExposeEnabled: {"Account peer expose enabled", "account.setting.peer.expose.enable"},
|
||||
AccountPeerExposeDisabled: {"Account peer expose disabled", "account.setting.peer.expose.disable"},
|
||||
|
||||
AccountMetricsPushEnabled: {"Account metrics push enabled", "account.setting.metrics.push.enable"},
|
||||
AccountMetricsPushDisabled: {"Account metrics push disabled", "account.setting.metrics.push.disable"},
|
||||
|
||||
AccountLocalMfaEnabled: {"Account local MFA enabled", "account.setting.local.mfa.enable"},
|
||||
AccountLocalMfaDisabled: {"Account local MFA disabled", "account.setting.local.mfa.disable"},
|
||||
|
||||
|
||||
@@ -1663,7 +1663,7 @@ func addPeerToAccount(t *testing.T, manager *DefaultAccountManager, _, setupKeyK
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
peer, _, _, _, err := manager.AddPeer(context.Background(), "", setupKeyKey, "", &nbpeer.Peer{
|
||||
peer, _, _, err := manager.AddPeer(context.Background(), "", setupKeyKey, "", &nbpeer.Peer{
|
||||
Key: key.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: key.PublicKey().String()},
|
||||
}, false)
|
||||
|
||||
@@ -298,11 +298,11 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account
|
||||
return nil, err
|
||||
}
|
||||
|
||||
savedPeer1, _, _, _, err := am.AddPeer(context.Background(), "", "", dnsAdminUserID, peer1, false)
|
||||
savedPeer1, _, _, err := am.AddPeer(context.Background(), "", "", dnsAdminUserID, peer1, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, _, _, _, err = am.AddPeer(context.Background(), "", "", dnsAdminUserID, peer2, false)
|
||||
_, _, _, err = am.AddPeer(context.Background(), "", "", dnsAdminUserID, peer2, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestGroupIPv6Assignment(t *testing.T) {
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
peer, _, _, _, err := am.AddPeer(ctx, "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer, _, _, err := am.AddPeer(ctx, "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: key.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "ipv6-test-host"},
|
||||
}, false)
|
||||
|
||||
@@ -277,6 +277,9 @@ func (h *handler) updateAccountRequestSettings(req api.PutApiAccountsAccountIdJS
|
||||
if req.Settings.AutoUpdateAlways != nil {
|
||||
returnSettings.AutoUpdateAlways = *req.Settings.AutoUpdateAlways
|
||||
}
|
||||
if req.Settings.MetricsPushEnabled != nil {
|
||||
returnSettings.MetricsPushEnabled = *req.Settings.MetricsPushEnabled
|
||||
}
|
||||
if req.Settings.LocalMfaEnabled != nil {
|
||||
returnSettings.LocalMfaEnabled = *req.Settings.LocalMfaEnabled
|
||||
}
|
||||
@@ -412,6 +415,7 @@ func toAccountResponse(accountID string, settings *types.Settings, meta *types.A
|
||||
DnsDomain: &settings.DNSDomain,
|
||||
AutoUpdateVersion: &settings.AutoUpdateVersion,
|
||||
AutoUpdateAlways: &settings.AutoUpdateAlways,
|
||||
MetricsPushEnabled: &settings.MetricsPushEnabled,
|
||||
Ipv6EnabledGroups: &settings.IPv6EnabledGroups,
|
||||
EmbeddedIdpEnabled: &settings.EmbeddedIdpEnabled,
|
||||
LocalAuthDisabled: &settings.LocalAuthDisabled,
|
||||
|
||||
@@ -129,6 +129,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
||||
DnsDomain: sr(""),
|
||||
AutoUpdateAlways: br(false),
|
||||
AutoUpdateVersion: sr(""),
|
||||
MetricsPushEnabled: br(false),
|
||||
EmbeddedIdpEnabled: br(false),
|
||||
LocalAuthDisabled: br(false),
|
||||
LocalMfaEnabled: br(false),
|
||||
@@ -156,6 +157,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
||||
DnsDomain: sr(""),
|
||||
AutoUpdateAlways: br(false),
|
||||
AutoUpdateVersion: sr(""),
|
||||
MetricsPushEnabled: br(false),
|
||||
EmbeddedIdpEnabled: br(false),
|
||||
LocalAuthDisabled: br(false),
|
||||
LocalMfaEnabled: br(false),
|
||||
@@ -183,6 +185,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
||||
DnsDomain: sr(""),
|
||||
AutoUpdateAlways: br(false),
|
||||
AutoUpdateVersion: sr("latest"),
|
||||
MetricsPushEnabled: br(false),
|
||||
EmbeddedIdpEnabled: br(false),
|
||||
LocalAuthDisabled: br(false),
|
||||
LocalMfaEnabled: br(false),
|
||||
@@ -210,6 +213,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
||||
DnsDomain: sr(""),
|
||||
AutoUpdateAlways: br(false),
|
||||
AutoUpdateVersion: sr(""),
|
||||
MetricsPushEnabled: br(false),
|
||||
EmbeddedIdpEnabled: br(false),
|
||||
LocalAuthDisabled: br(false),
|
||||
LocalMfaEnabled: br(false),
|
||||
@@ -237,6 +241,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
||||
DnsDomain: sr(""),
|
||||
AutoUpdateAlways: br(false),
|
||||
AutoUpdateVersion: sr(""),
|
||||
MetricsPushEnabled: br(false),
|
||||
EmbeddedIdpEnabled: br(false),
|
||||
LocalAuthDisabled: br(false),
|
||||
LocalMfaEnabled: br(false),
|
||||
@@ -264,6 +269,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
||||
DnsDomain: sr(""),
|
||||
AutoUpdateAlways: br(false),
|
||||
AutoUpdateVersion: sr(""),
|
||||
MetricsPushEnabled: br(false),
|
||||
EmbeddedIdpEnabled: br(false),
|
||||
LocalAuthDisabled: br(false),
|
||||
LocalMfaEnabled: br(false),
|
||||
|
||||
@@ -479,7 +479,7 @@ func (h *Handler) CreateTemporaryAccess(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
peer, _, _, _, err := h.accountManager.AddPeer(r.Context(), userAuth.AccountId, "", userAuth.UserId, newPeer, true)
|
||||
peer, _, _, err := h.accountManager.AddPeer(r.Context(), userAuth.AccountId, "", userAuth.UserId, newPeer, true)
|
||||
if err != nil {
|
||||
util.WriteError(r.Context(), err, w)
|
||||
return
|
||||
|
||||
@@ -728,7 +728,7 @@ func Test_LoginPerformance(t *testing.T) {
|
||||
}
|
||||
|
||||
login := func() error {
|
||||
_, _, _, _, err = am.LoginPeer(context.Background(), peerLogin)
|
||||
_, _, _, err = am.LoginPeer(context.Background(), peerLogin)
|
||||
if err != nil {
|
||||
t.Logf("failed to login peer: %v", err)
|
||||
return err
|
||||
@@ -746,7 +746,7 @@ func Test_LoginPerformance(t *testing.T) {
|
||||
|
||||
go func(peerLogin types.PeerLogin, counterStart *int32) {
|
||||
defer wgPeer.Done()
|
||||
_, _, _, _, err = am.LoginPeer(context.Background(), peerLogin)
|
||||
_, _, _, err = am.LoginPeer(context.Background(), peerLogin)
|
||||
if err != nil {
|
||||
t.Logf("failed to login peer: %v", err)
|
||||
return
|
||||
|
||||
@@ -45,7 +45,7 @@ type MockAccountManager struct {
|
||||
DeletePeerFunc func(ctx context.Context, accountID, peerKey, userID string) error
|
||||
GetNetworkMapFunc func(ctx context.Context, peerKey string) (*types.NetworkMap, error)
|
||||
GetPeerNetworkFunc func(ctx context.Context, peerKey string) (*types.Network, error)
|
||||
AddPeerFunc func(ctx context.Context, accountID string, setupKey string, userId string, peer *nbpeer.Peer, temporary bool) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error)
|
||||
AddPeerFunc func(ctx context.Context, accountID string, setupKey string, userId string, peer *nbpeer.Peer, temporary bool) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error)
|
||||
GetGroupFunc func(ctx context.Context, accountID, groupID, userID string) (*types.Group, error)
|
||||
GetAllGroupsFunc func(ctx context.Context, accountID, userID string) ([]*types.Group, error)
|
||||
GetGroupByNameFunc func(ctx context.Context, groupName, accountID, userID string) (*types.Group, error)
|
||||
@@ -98,7 +98,7 @@ type MockAccountManager struct {
|
||||
SaveDNSSettingsFunc func(ctx context.Context, accountID, userID string, dnsSettingsToSave *types.DNSSettings) error
|
||||
GetPeerFunc func(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error)
|
||||
UpdateAccountSettingsFunc func(ctx context.Context, accountID, userID string, newSettings *types.Settings) (*types.Settings, error)
|
||||
LoginPeerFunc func(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error)
|
||||
LoginPeerFunc func(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error)
|
||||
ExtendPeerSessionFunc func(ctx context.Context, peerPubKey, userID string) (time.Time, error)
|
||||
SyncPeerFunc func(ctx context.Context, sync types.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, int64, error)
|
||||
InviteUserFunc func(ctx context.Context, accountID string, initiatorUserID string, targetUserEmail string) error
|
||||
@@ -424,11 +424,11 @@ func (am *MockAccountManager) AddPeer(
|
||||
userId string,
|
||||
peer *nbpeer.Peer,
|
||||
temporary bool,
|
||||
) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
if am.AddPeerFunc != nil {
|
||||
return am.AddPeerFunc(ctx, accountID, setupKey, userId, peer, temporary)
|
||||
}
|
||||
return nil, nil, nil, false, status.Errorf(codes.Unimplemented, "method AddPeer is not implemented")
|
||||
return nil, nil, nil, status.Errorf(codes.Unimplemented, "method AddPeer is not implemented")
|
||||
}
|
||||
|
||||
// GetGroupByName mock implementation of GetGroupByName from server.AccountManager interface
|
||||
@@ -862,11 +862,11 @@ func (am *MockAccountManager) UpdateAccountSettings(ctx context.Context, account
|
||||
}
|
||||
|
||||
// LoginPeer mocks LoginPeer of the AccountManager interface
|
||||
func (am *MockAccountManager) LoginPeer(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
func (am *MockAccountManager) LoginPeer(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
if am.LoginPeerFunc != nil {
|
||||
return am.LoginPeerFunc(ctx, login)
|
||||
}
|
||||
return nil, nil, nil, false, status.Errorf(codes.Unimplemented, "method LoginPeer is not implemented")
|
||||
return nil, nil, nil, status.Errorf(codes.Unimplemented, "method LoginPeer is not implemented")
|
||||
}
|
||||
|
||||
// ExtendPeerSession mocks ExtendPeerSession of the AccountManager interface
|
||||
|
||||
@@ -896,11 +896,11 @@ func initTestNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, _, _, _, err = am.AddPeer(context.Background(), "", "", userID, peer1, false)
|
||||
_, _, _, err = am.AddPeer(context.Background(), "", "", userID, peer1, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, _, _, _, err = am.AddPeer(context.Background(), "", "", userID, peer2, false)
|
||||
_, _, _, err = am.AddPeer(context.Background(), "", "", userID, peer2, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -718,10 +718,10 @@ func (am *DefaultAccountManager) handleSetupKeyAddedPeer(ctx context.Context, en
|
||||
// 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(ctx context.Context, accountID, setupKey, userID string, peer *nbpeer.Peer, temporary bool) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKey, userID string, peer *nbpeer.Peer, temporary bool) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
if setupKey == "" && userID == "" && !peer.ProxyMeta.Embedded {
|
||||
// no auth method provided => reject access
|
||||
return nil, nil, nil, false, status.Errorf(status.Unauthenticated, "no peer auth method provided, please use a setup key or interactive SSO login")
|
||||
return nil, nil, nil, status.Errorf(status.Unauthenticated, "no peer auth method provided, please use a setup key or interactive SSO login")
|
||||
}
|
||||
|
||||
upperKey := strings.ToUpper(setupKey)
|
||||
@@ -737,7 +737,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
// The connecting peer should be able to recover with a retry.
|
||||
_, err := am.Store.GetPeerByPeerPubKey(ctx, store.LockingStrengthNone, peer.Key)
|
||||
if err == nil {
|
||||
return nil, nil, nil, false, status.Errorf(status.PreconditionFailed, "peer has been already registered")
|
||||
return nil, nil, nil, status.Errorf(status.PreconditionFailed, "peer has been already registered")
|
||||
}
|
||||
|
||||
opEvent := &activity.Event{
|
||||
@@ -748,7 +748,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
|
||||
peerAddConfig, err := am.processPeerAddAuth(ctx, accountID, userID, encodedHashedKey, peer, temporary, addedByUser, addedBySetupKey, opEvent)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
accountID = peerAddConfig.AccountID
|
||||
ephemeral := peerAddConfig.Ephemeral
|
||||
@@ -763,7 +763,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
}
|
||||
|
||||
if err := domain.ValidateDomainsList(peer.ExtraDNSLabels); err != nil {
|
||||
return nil, nil, nil, false, status.Errorf(status.InvalidArgument, "invalid extra DNS labels: %v", err)
|
||||
return nil, nil, nil, status.Errorf(status.InvalidArgument, "invalid extra DNS labels: %v", err)
|
||||
}
|
||||
|
||||
registrationTime := time.Now().UTC()
|
||||
@@ -789,7 +789,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
}
|
||||
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("failed to get account settings: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to get account settings: %w", err)
|
||||
}
|
||||
|
||||
if am.geo != nil && newPeer.Location.ConnectionIP != nil {
|
||||
@@ -807,30 +807,30 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
|
||||
network, err := am.Store.GetAccountNetwork(ctx, store.LockingStrengthNone, accountID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("failed getting network: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed getting network: %w", err)
|
||||
}
|
||||
|
||||
maxAttempts := 10
|
||||
for attempt := 1; attempt <= maxAttempts; attempt++ {
|
||||
netPrefix, err := netip.ParsePrefix(network.Net.String())
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("parse network prefix: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("parse network prefix: %w", err)
|
||||
}
|
||||
freeIP, err := types.AllocateRandomPeerIP(netPrefix)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("failed to get free IP: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to get free IP: %w", err)
|
||||
}
|
||||
|
||||
var freeLabel string
|
||||
if ephemeral || attempt > 1 {
|
||||
freeLabel, err = getPeerIPDNSLabel(freeIP, peer.Meta.Hostname)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
}
|
||||
} else {
|
||||
freeLabel, err = nbdns.GetParsedDomainLabel(peer.Meta.Hostname)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
}
|
||||
}
|
||||
newPeer.DNSLabel = freeLabel
|
||||
@@ -852,11 +852,11 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
if allocate {
|
||||
v6Prefix, err := netip.ParsePrefix(network.NetV6.String())
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("parse IPv6 prefix: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("parse IPv6 prefix: %w", err)
|
||||
}
|
||||
freeIPv6, err := types.AllocateRandomPeerIPv6(v6Prefix)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("allocate peer IPv6: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("allocate peer IPv6: %w", err)
|
||||
}
|
||||
newPeer.IPv6 = freeIPv6
|
||||
}
|
||||
@@ -929,10 +929,10 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, nil, nil, false, fmt.Errorf("failed to add peer to database: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to add peer to database: %w", err)
|
||||
}
|
||||
if newPeer == nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("new peer is nil")
|
||||
return nil, nil, nil, fmt.Errorf("new peer is nil")
|
||||
}
|
||||
|
||||
opEvent.TargetID = newPeer.ID
|
||||
@@ -940,8 +940,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
if !addedByUser {
|
||||
opEvent.Meta["setup_key_name"] = peerAddConfig.SetupKeyName
|
||||
}
|
||||
requiresApproval := newPeer.Status != nil && newPeer.Status.RequiresApproval
|
||||
if requiresApproval {
|
||||
if newPeer.Status != nil && newPeer.Status.RequiresApproval {
|
||||
opEvent.Meta["pending_approval"] = true
|
||||
}
|
||||
|
||||
@@ -949,18 +948,18 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, accountID, setupKe
|
||||
am.StoreEvent(ctx, opEvent.InitiatorID, opEvent.TargetID, opEvent.AccountID, opEvent.Activity, opEvent.Meta)
|
||||
}
|
||||
|
||||
network, postureChecks, enableSSH, err := getPeerLoginInfo(ctx, am.Store, accountID, newPeer, !requiresApproval)
|
||||
p, nmap, pc, _, err := am.networkMapController.GetValidatedPeerWithMap(ctx, false, accountID, newPeer)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return p, nmap, pc, err
|
||||
}
|
||||
|
||||
changedPeerIDs := []string{newPeer.ID}
|
||||
affectedPeerIDs := am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, changedPeerIDs)
|
||||
affectedPeerIDs := affectedPeerIDsFromNetworkMap(nmap, newPeer.ID)
|
||||
if err := am.networkMapController.OnPeersAdded(ctx, accountID, changedPeerIDs, affectedPeerIDs); err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to update network map cache for peer %s: %v", newPeer.ID, err)
|
||||
}
|
||||
|
||||
return newPeer, network, postureChecks, enableSSH, nil
|
||||
return p, nmap, pc, nil
|
||||
}
|
||||
|
||||
func getPeerIPDNSLabel(ip netip.Addr, peerHostName string) (string, error) {
|
||||
@@ -982,6 +981,7 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
||||
var peer *nbpeer.Peer
|
||||
var updated, versionChanged, ipv6CapabilityChanged bool
|
||||
var err error
|
||||
var postureChecks []*posture.Checks
|
||||
var peerGroupIDs []string
|
||||
|
||||
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID)
|
||||
@@ -1024,6 +1024,11 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
||||
if err = transaction.SavePeer(ctx, accountID, peer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
postureChecks, err = getPeerPostureChecks(ctx, transaction, accountID, peer.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -1036,21 +1041,20 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
nmap, resPostureChecks, dnsFwdPort, err := am.networkMapController.GetValidatedPeerWithMap(ctx, peerNotValid, accountID, peer.ID)
|
||||
resPeer, nmap, resPostureChecks, dnsFwdPort, err := am.networkMapController.GetValidatedPeerWithMap(ctx, peerNotValid, accountID, peer)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
|
||||
if isStatusChanged || sync.UpdateAccountPeers || ipv6CapabilityChanged || updated || versionChanged {
|
||||
if isStatusChanged || sync.UpdateAccountPeers || ipv6CapabilityChanged || (updated && (len(postureChecks) > 0 || versionChanged)) {
|
||||
changedPeerIDs := []string{peer.ID}
|
||||
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, peerNotValid, updated)
|
||||
log.Infof("Sync: peer %s affected peers %s", peer.ID, affectedPeerIDs)
|
||||
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, peerNotValid, updated, len(postureChecks) > 0)
|
||||
if err = am.networkMapController.OnPeersUpdated(ctx, accountID, changedPeerIDs, affectedPeerIDs); err != nil {
|
||||
return nil, nil, nil, 0, fmt.Errorf("notify network map controller of peer update: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return peer, nmap, resPostureChecks, dnsFwdPort, nil
|
||||
return resPeer, nmap, resPostureChecks, dnsFwdPort, nil
|
||||
}
|
||||
|
||||
// syncPeerAffectedPeers resolves the peers affected by a SyncPeer change. The
|
||||
@@ -1061,8 +1065,8 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
||||
// metadata change that flips a posture result removes this peer from others'
|
||||
// maps asymmetrically; that case (and an invalid peer, whose map is empty) falls
|
||||
// back to the resolver.
|
||||
func (am *DefaultAccountManager) syncPeerAffectedPeers(ctx context.Context, accountID, peerID string, nmap *types.NetworkMap, peerNotValid, metaUpdated bool) []string {
|
||||
if peerNotValid || metaUpdated {
|
||||
func (am *DefaultAccountManager) syncPeerAffectedPeers(ctx context.Context, accountID, peerID string, nmap *types.NetworkMap, peerNotValid, metaUpdated, hasPostureChecks bool) []string {
|
||||
if peerNotValid || (metaUpdated && hasPostureChecks) {
|
||||
return am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, []string{peerID})
|
||||
}
|
||||
return affectedPeerIDsFromNetworkMap(nmap, peerID)
|
||||
@@ -1081,7 +1085,7 @@ func (am *DefaultAccountManager) markConnectedAffectedPeers(ctx context.Context,
|
||||
return affectedPeerIDsFromNetworkMap(nmap, peerID)
|
||||
}
|
||||
|
||||
func (am *DefaultAccountManager) handlePeerLoginNotFound(ctx context.Context, login types.PeerLogin, err error) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
func (am *DefaultAccountManager) handlePeerLoginNotFound(ctx context.Context, login types.PeerLogin, err error) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
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.
|
||||
@@ -1097,12 +1101,12 @@ func (am *DefaultAccountManager) handlePeerLoginNotFound(ctx context.Context, lo
|
||||
}
|
||||
|
||||
log.WithContext(ctx).Errorf("failed while logging in peer %s: %v", login.WireGuardPubKey, err)
|
||||
return nil, nil, nil, false, status.Errorf(status.Internal, "failed while logging in peer")
|
||||
return nil, nil, nil, status.Errorf(status.Internal, "failed while logging in peer")
|
||||
}
|
||||
|
||||
// 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(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.Network, []*posture.Checks, bool, error) {
|
||||
func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) {
|
||||
accountID, err := am.Store.GetAccountIDByPeerPubKey(ctx, login.WireGuardPubKey)
|
||||
if err != nil {
|
||||
return am.handlePeerLoginNotFound(ctx, login, err)
|
||||
@@ -1114,17 +1118,20 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
|
||||
if login.UserID == "" {
|
||||
err = am.checkIFPeerNeedsLoginWithoutLock(ctx, accountID, login)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var peer *nbpeer.Peer
|
||||
var shouldStorePeer bool
|
||||
var updateRemotePeers bool
|
||||
var isPeerUpdated bool
|
||||
var ipv6CapabilityChanged bool
|
||||
var postureChecks []*posture.Checks
|
||||
var peerGroupIDs []string
|
||||
|
||||
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
err = am.Store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
||||
@@ -1133,6 +1140,9 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
|
||||
return err
|
||||
}
|
||||
|
||||
// this flag prevents unnecessary calls to the persistent store.
|
||||
shouldStorePeer := false
|
||||
|
||||
if login.UserID != "" {
|
||||
if peer.UserID != login.UserID {
|
||||
log.Warnf("user mismatch when logging in peer %s: peer user %s, login user %s ", peer.ID, peer.UserID, login.UserID)
|
||||
@@ -1146,6 +1156,7 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
|
||||
|
||||
if changed {
|
||||
shouldStorePeer = true
|
||||
updateRemotePeers = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1154,9 +1165,23 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
|
||||
return err
|
||||
}
|
||||
|
||||
oldHasIPv6Cap := peer.HasCapability(nbpeer.PeerCapabilityIPv6Overlay)
|
||||
isPeerUpdated, _ = peer.UpdateMetaIfNew(login.Meta)
|
||||
ipv6CapabilityChanged = oldHasIPv6Cap != peer.HasCapability(nbpeer.PeerCapabilityIPv6Overlay)
|
||||
if isPeerUpdated {
|
||||
am.metrics.AccountManagerMetrics().CountPeerMetUpdate()
|
||||
shouldStorePeer = true
|
||||
|
||||
postureChecks, err = getPeerPostureChecks(ctx, transaction, accountID, peer.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if peer.SSHKey != login.SSHKey {
|
||||
peer.SSHKey = login.SSHKey
|
||||
shouldStorePeer = true
|
||||
updateRemotePeers = true
|
||||
}
|
||||
|
||||
if !peer.AllowExtraDNSLabels && len(login.ExtraDNSLabels) > 0 {
|
||||
@@ -1169,37 +1194,31 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
|
||||
}
|
||||
}
|
||||
|
||||
peer.UpdateMetaIfNew(login.Meta)
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
isRequiresApproval, isStatusChanged, err := am.integratedPeerValidator.IsNotValidPeer(ctx, accountID, peer, peerGroupIDs, settings.Extra)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
network, postureChecks, enableSSH, err := getPeerLoginInfo(ctx, am.Store, accountID, peer, !isRequiresApproval)
|
||||
p, nmap, pc, _, err := am.networkMapController.GetValidatedPeerWithMap(ctx, isRequiresApproval, accountID, peer)
|
||||
if err != nil {
|
||||
return nil, nil, nil, false, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
changedPeerIDs := []string{peer.ID}
|
||||
affectedPeerIDs := am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, changedPeerIDs)
|
||||
log.Infof("Login: peer %s affected peers %s", peer.ID, affectedPeerIDs)
|
||||
|
||||
if isStatusChanged || shouldStorePeer {
|
||||
if updateRemotePeers || isStatusChanged || ipv6CapabilityChanged || (isPeerUpdated && len(postureChecks) > 0) {
|
||||
changedPeerIDs := []string{peer.ID}
|
||||
affectedPeerIDs := am.resolveAffectedPeersForPeerChanges(ctx, am.Store, accountID, changedPeerIDs)
|
||||
affectedPeerIDs := am.syncPeerAffectedPeers(ctx, accountID, peer.ID, nmap, isRequiresApproval, isPeerUpdated, len(postureChecks) > 0)
|
||||
if err = am.networkMapController.OnPeersUpdated(ctx, accountID, changedPeerIDs, affectedPeerIDs); err != nil {
|
||||
return nil, nil, nil, false, fmt.Errorf("notify network map controller of peer update: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("notify network map controller of peer update: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return peer, network, postureChecks, enableSSH, nil
|
||||
return p, nmap, pc, nil
|
||||
}
|
||||
|
||||
// ExtendPeerSession refreshes the peer's SSO session deadline by updating
|
||||
@@ -1275,50 +1294,6 @@ func (am *DefaultAccountManager) ExtendPeerSession(ctx context.Context, peerPubK
|
||||
return refreshed.SessionExpiresAt(settings.PeerLoginExpirationEnabled, settings.PeerLoginExpiration), nil
|
||||
}
|
||||
|
||||
// getPeerLoginInfo computes the login/register response data (network, posture
|
||||
// checks, SSH) from the store without building the peer's full network map.
|
||||
func getPeerLoginInfo(ctx context.Context, transaction store.Store, accountID string, peer *nbpeer.Peer, isValid bool) (*types.Network, []*posture.Checks, bool, error) {
|
||||
network, err := transaction.GetAccountNetwork(ctx, store.LockingStrengthNone, accountID)
|
||||
if err != nil {
|
||||
return nil, nil, false, fmt.Errorf("get account network: %w", err)
|
||||
}
|
||||
|
||||
if !isValid {
|
||||
return network, nil, false, nil
|
||||
}
|
||||
|
||||
postureChecks, err := getPeerPostureChecks(ctx, transaction, accountID, peer.ID)
|
||||
if err != nil {
|
||||
return nil, nil, false, err
|
||||
}
|
||||
|
||||
_, err = isPeerSSHEnabled(ctx, transaction, accountID, peer)
|
||||
if err != nil {
|
||||
return nil, nil, false, err
|
||||
}
|
||||
|
||||
return network, postureChecks, true, nil
|
||||
}
|
||||
|
||||
func isPeerSSHEnabled(ctx context.Context, transaction store.Store, accountID string, peer *nbpeer.Peer) (bool, error) {
|
||||
policies, err := transaction.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
peerGroups, err := transaction.GetPeerGroups(ctx, store.LockingStrengthNone, accountID, peer.ID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
peerGroupIDs := make(map[string]struct{}, len(peerGroups))
|
||||
for _, g := range peerGroups {
|
||||
peerGroupIDs[g.ID] = struct{}{}
|
||||
}
|
||||
|
||||
return types.PeerSSHEnabledFromPolicies(policies, peer.ID, peerGroupIDs, peer.SSHEnabled), nil
|
||||
}
|
||||
|
||||
// getPeerPostureChecks returns the posture checks for the peer.
|
||||
func getPeerPostureChecks(ctx context.Context, transaction store.Store, accountID, peerID string) ([]*posture.Checks, error) {
|
||||
policies, err := transaction.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/util"
|
||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||
)
|
||||
@@ -166,7 +162,49 @@ type PeerSystemMeta struct { //nolint:revive
|
||||
}
|
||||
|
||||
func (p PeerSystemMeta) isEqual(other PeerSystemMeta) bool {
|
||||
return len(metaDiff(p, other)) == 0
|
||||
sort.Slice(p.NetworkAddresses, func(i, j int) bool {
|
||||
return p.NetworkAddresses[i].Mac < p.NetworkAddresses[j].Mac
|
||||
})
|
||||
sort.Slice(other.NetworkAddresses, func(i, j int) bool {
|
||||
return other.NetworkAddresses[i].Mac < other.NetworkAddresses[j].Mac
|
||||
})
|
||||
equalNetworkAddresses := slices.EqualFunc(p.NetworkAddresses, other.NetworkAddresses, func(addr NetworkAddress, oAddr NetworkAddress) bool {
|
||||
return addr.Mac == oAddr.Mac && addr.NetIP == oAddr.NetIP
|
||||
})
|
||||
if !equalNetworkAddresses {
|
||||
return false
|
||||
}
|
||||
|
||||
sort.Slice(p.Files, func(i, j int) bool {
|
||||
return p.Files[i].Path < p.Files[j].Path
|
||||
})
|
||||
sort.Slice(other.Files, func(i, j int) bool {
|
||||
return other.Files[i].Path < other.Files[j].Path
|
||||
})
|
||||
equalFiles := slices.EqualFunc(p.Files, other.Files, func(file File, oFile File) bool {
|
||||
return file.Path == oFile.Path && file.Exist == oFile.Exist && file.ProcessIsRunning == oFile.ProcessIsRunning
|
||||
})
|
||||
if !equalFiles {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.Hostname == other.Hostname &&
|
||||
p.GoOS == other.GoOS &&
|
||||
p.Kernel == other.Kernel &&
|
||||
p.KernelVersion == other.KernelVersion &&
|
||||
p.Core == other.Core &&
|
||||
p.Platform == other.Platform &&
|
||||
p.OS == other.OS &&
|
||||
p.OSVersion == other.OSVersion &&
|
||||
p.WtVersion == other.WtVersion &&
|
||||
p.UIVersion == other.UIVersion &&
|
||||
p.SystemSerialNumber == other.SystemSerialNumber &&
|
||||
p.SystemProductName == other.SystemProductName &&
|
||||
p.SystemManufacturer == other.SystemManufacturer &&
|
||||
p.Environment.Cloud == other.Environment.Cloud &&
|
||||
p.Environment.Platform == other.Environment.Platform &&
|
||||
p.Flags.isEqual(other.Flags) &&
|
||||
capabilitiesEqual(p.Capabilities, other.Capabilities)
|
||||
}
|
||||
|
||||
func (p PeerSystemMeta) isEmpty() bool {
|
||||
@@ -209,12 +247,12 @@ func (p *Peer) SupportsSourcePrefixes() bool {
|
||||
return p.HasCapability(PeerCapabilitySourcePrefixes)
|
||||
}
|
||||
|
||||
func (a PeerSystemMeta) CapabilitiesEqual(b []int32) bool {
|
||||
if len(a.Capabilities) != len(b) {
|
||||
func capabilitiesEqual(a, b []int32) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
set := make(map[int32]struct{}, len(a.Capabilities))
|
||||
for _, c := range a.Capabilities {
|
||||
set := make(map[int32]struct{}, len(a))
|
||||
for _, c := range a {
|
||||
set[c] = struct{}{}
|
||||
}
|
||||
for _, c := range b {
|
||||
@@ -270,113 +308,14 @@ func (p *Peer) UpdateMetaIfNew(meta PeerSystemMeta) (updated, versionChanged boo
|
||||
meta.UIVersion = p.Meta.UIVersion
|
||||
}
|
||||
|
||||
oldVersion := p.Meta.WtVersion
|
||||
|
||||
diff := metaDiff(p.Meta, meta)
|
||||
if len(diff) != 0 {
|
||||
p.Meta = meta
|
||||
updated = true
|
||||
if p.Meta.isEqual(meta) {
|
||||
return updated, versionChanged
|
||||
}
|
||||
|
||||
versionInfo := ""
|
||||
if versionChanged {
|
||||
versionInfo = fmt.Sprintf("version changed: %s -> %s, ", oldVersion, meta.WtVersion)
|
||||
}
|
||||
|
||||
if versionChanged || updated {
|
||||
log.WithFields(log.Fields{"peer": p.ID, "key": p.Key}).
|
||||
Infof("peer meta updated, %s%d field(s) changed: %s", versionInfo, len(diff), strings.Join(diff, ", "))
|
||||
}
|
||||
|
||||
p.Meta = meta
|
||||
updated = true
|
||||
return updated, versionChanged
|
||||
}
|
||||
|
||||
// metaDiff returns a human-readable list of the fields that differ between the
|
||||
// old and new meta, each formatted as `field: <old> -> <new>`. It is the single
|
||||
// source of truth for meta comparison: isEqual reports equality as an empty
|
||||
// diff, so the log line can never disagree with the change decision. Slices are
|
||||
// cloned before sorting, so callers' meta is not mutated.
|
||||
func metaDiff(old, new PeerSystemMeta) []string {
|
||||
var diff []string
|
||||
add := func(field string, oldVal, newVal any) {
|
||||
diff = append(diff, fmt.Sprintf("%s: %v -> %v", field, oldVal, newVal))
|
||||
}
|
||||
|
||||
if old.Hostname != new.Hostname {
|
||||
add("hostname", old.Hostname, new.Hostname)
|
||||
}
|
||||
if old.GoOS != new.GoOS {
|
||||
add("goos", old.GoOS, new.GoOS)
|
||||
}
|
||||
if old.Kernel != new.Kernel {
|
||||
add("kernel", old.Kernel, new.Kernel)
|
||||
}
|
||||
if old.KernelVersion != new.KernelVersion {
|
||||
add("kernel_version", old.KernelVersion, new.KernelVersion)
|
||||
}
|
||||
if old.Core != new.Core {
|
||||
add("core", old.Core, new.Core)
|
||||
}
|
||||
if old.Platform != new.Platform {
|
||||
add("platform", old.Platform, new.Platform)
|
||||
}
|
||||
if old.OS != new.OS {
|
||||
add("os", old.OS, new.OS)
|
||||
}
|
||||
if old.OSVersion != new.OSVersion {
|
||||
add("os_version", old.OSVersion, new.OSVersion)
|
||||
}
|
||||
if old.WtVersion != new.WtVersion {
|
||||
add("wt_version", old.WtVersion, new.WtVersion)
|
||||
}
|
||||
if old.UIVersion != new.UIVersion {
|
||||
add("ui_version", old.UIVersion, new.UIVersion)
|
||||
}
|
||||
if old.SystemSerialNumber != new.SystemSerialNumber {
|
||||
add("system_serial_number", old.SystemSerialNumber, new.SystemSerialNumber)
|
||||
}
|
||||
if old.SystemProductName != new.SystemProductName {
|
||||
add("system_product_name", old.SystemProductName, new.SystemProductName)
|
||||
}
|
||||
if old.SystemManufacturer != new.SystemManufacturer {
|
||||
add("system_manufacturer", old.SystemManufacturer, new.SystemManufacturer)
|
||||
}
|
||||
if old.Environment.Cloud != new.Environment.Cloud {
|
||||
add("environment_cloud", old.Environment.Cloud, new.Environment.Cloud)
|
||||
}
|
||||
if old.Environment.Platform != new.Environment.Platform {
|
||||
add("environment_platform", old.Environment.Platform, new.Environment.Platform)
|
||||
}
|
||||
if !old.Flags.isEqual(new.Flags) {
|
||||
add("flags", fmt.Sprintf("%+v", old.Flags), fmt.Sprintf("%+v", new.Flags))
|
||||
}
|
||||
if !old.CapabilitiesEqual(new.Capabilities) {
|
||||
add("capabilities", old.Capabilities, new.Capabilities)
|
||||
}
|
||||
|
||||
oldAddrs := slices.Clone(old.NetworkAddresses)
|
||||
newAddrs := slices.Clone(new.NetworkAddresses)
|
||||
sort.Slice(oldAddrs, func(i, j int) bool { return oldAddrs[i].Mac < oldAddrs[j].Mac })
|
||||
sort.Slice(newAddrs, func(i, j int) bool { return newAddrs[i].Mac < newAddrs[j].Mac })
|
||||
if !slices.EqualFunc(oldAddrs, newAddrs, func(a, b NetworkAddress) bool {
|
||||
return a.Mac == b.Mac && a.NetIP == b.NetIP
|
||||
}) {
|
||||
add("network_addresses", fmt.Sprintf("%v", oldAddrs), fmt.Sprintf("%v", newAddrs))
|
||||
}
|
||||
|
||||
oldFiles := slices.Clone(old.Files)
|
||||
newFiles := slices.Clone(new.Files)
|
||||
sort.Slice(oldFiles, func(i, j int) bool { return oldFiles[i].Path < oldFiles[j].Path })
|
||||
sort.Slice(newFiles, func(i, j int) bool { return newFiles[i].Path < newFiles[j].Path })
|
||||
if !slices.EqualFunc(oldFiles, newFiles, func(a, b File) bool {
|
||||
return a.Path == b.Path && a.Exist == b.Exist && a.ProcessIsRunning == b.ProcessIsRunning
|
||||
}) {
|
||||
add("files", fmt.Sprintf("%v", oldFiles), fmt.Sprintf("%v", newFiles))
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
// GetLastLogin returns the last login time of the peer.
|
||||
func (p *Peer) GetLastLogin() time.Time {
|
||||
if p.LastLogin != nil {
|
||||
|
||||
@@ -205,7 +205,7 @@ func testGetNetworkMapGeneral(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"},
|
||||
}, false)
|
||||
@@ -219,7 +219,7 @@ func testGetNetworkMapGeneral(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
@@ -278,7 +278,7 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"},
|
||||
}, false)
|
||||
@@ -292,7 +292,7 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
peer2, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
@@ -454,7 +454,7 @@ func TestAccountManager_GetPeerNetwork(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"},
|
||||
}, false)
|
||||
@@ -468,7 +468,7 @@ func TestAccountManager_GetPeerNetwork(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
@@ -526,7 +526,7 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", "", someUser, &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", "", someUser, &nbpeer.Peer{
|
||||
Key: peerKey1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
@@ -542,7 +542,7 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) {
|
||||
}
|
||||
|
||||
// the second peer added with a setup key
|
||||
peer2, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", &nbpeer.Peer{
|
||||
Key: peerKey2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
@@ -698,7 +698,7 @@ func TestDefaultAccountManager_GetPeers(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", someUser, &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", someUser, &nbpeer.Peer{
|
||||
Key: peerKey1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"},
|
||||
}, false)
|
||||
@@ -707,7 +707,7 @@ func TestDefaultAccountManager_GetPeers(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", adminUser, &nbpeer.Peer{
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", adminUser, &nbpeer.Peer{
|
||||
Key: peerKey2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||
}, false)
|
||||
@@ -1047,7 +1047,11 @@ func testUpdateAccountPeers(t *testing.T) {
|
||||
|
||||
for _, channel := range peerChannels {
|
||||
update := <-channel
|
||||
assert.Nil(t, update.Update.NetbirdConfig)
|
||||
assert.NotNil(t, update.Update.NetbirdConfig)
|
||||
assert.Nil(t, update.Update.NetbirdConfig.Stuns)
|
||||
assert.Nil(t, update.Update.NetbirdConfig.Turns)
|
||||
assert.Nil(t, update.Update.NetbirdConfig.Signal)
|
||||
assert.Nil(t, update.Update.NetbirdConfig.Relay)
|
||||
assert.Equal(t, tc.peers, len(update.Update.NetworkMap.RemotePeers))
|
||||
assert.Equal(t, tc.peers*2, len(update.Update.NetworkMap.FirewallRules))
|
||||
}
|
||||
@@ -1332,7 +1336,7 @@ func Test_RegisterPeerByUser(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
addedPeer, _, _, _, err := am.AddPeer(context.Background(), "", "", existingUserID, newPeer, false)
|
||||
addedPeer, _, _, err := am.AddPeer(context.Background(), "", "", existingUserID, newPeer, false)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newPeer.ExtraDNSLabels, addedPeer.ExtraDNSLabels)
|
||||
|
||||
@@ -1465,7 +1469,7 @@ func Test_RegisterPeerBySetupKey(t *testing.T) {
|
||||
ExtraDNSLabels: newPeerTemplate.ExtraDNSLabels,
|
||||
}
|
||||
|
||||
addedPeer, _, _, _, err := am.AddPeer(context.Background(), "", tc.existingSetupKeyID, "", currentPeer, false)
|
||||
addedPeer, _, _, err := am.AddPeer(context.Background(), "", tc.existingSetupKeyID, "", currentPeer, false)
|
||||
|
||||
if tc.expectAddPeerError {
|
||||
require.Error(t, err, "Expected an error when adding peer with setup key: %s", tc.existingSetupKeyID)
|
||||
@@ -1577,7 +1581,7 @@ func Test_RegisterPeerRollbackOnFailure(t *testing.T) {
|
||||
SSHEnabled: false,
|
||||
}
|
||||
|
||||
_, _, _, _, err = am.AddPeer(context.Background(), "", faultyKey, "", newPeer, false)
|
||||
_, _, _, err = am.AddPeer(context.Background(), "", faultyKey, "", newPeer, false)
|
||||
require.Error(t, err)
|
||||
|
||||
_, err = s.GetPeerByPeerPubKey(context.Background(), store.LockingStrengthNone, newPeer.Key)
|
||||
@@ -1723,7 +1727,7 @@ func Test_LoginPeer(t *testing.T) {
|
||||
if sk.AllowExtraDNSLabels {
|
||||
currentPeer.ExtraDNSLabels = newPeerTemplate.ExtraDNSLabels
|
||||
}
|
||||
_, _, _, _, err = am.AddPeer(context.Background(), "", tc.setupKey, "", currentPeer, false)
|
||||
_, _, _, err = am.AddPeer(context.Background(), "", tc.setupKey, "", currentPeer, false)
|
||||
require.NoError(t, err, "Expected no error when adding peer with setup key: %s", tc.setupKey)
|
||||
|
||||
loginInput := types.PeerLogin{
|
||||
@@ -1739,12 +1743,12 @@ func Test_LoginPeer(t *testing.T) {
|
||||
loginInput.ExtraDNSLabels = tc.extraDNSLabels
|
||||
}
|
||||
|
||||
loggedinPeer, network, postureChecks, _, loginErr := am.LoginPeer(context.Background(), loginInput)
|
||||
loggedinPeer, networkMap, postureChecks, loginErr := am.LoginPeer(context.Background(), loginInput)
|
||||
if tc.expectLoginError {
|
||||
require.Error(t, loginErr, "Expected an error during LoginPeer with setup key: %s", tc.setupKey)
|
||||
assert.Contains(t, loginErr.Error(), tc.expectedErrorMsgSubstring, "Error message mismatch")
|
||||
assert.Nil(t, loggedinPeer, "LoggedinPeer should be nil on error")
|
||||
assert.Nil(t, network, "Network should be nil on error")
|
||||
assert.Nil(t, networkMap, "NetworkMap should be nil on error")
|
||||
assert.Nil(t, postureChecks, "PostureChecks should be empty or nil on error")
|
||||
return
|
||||
}
|
||||
@@ -1757,7 +1761,7 @@ func Test_LoginPeer(t *testing.T) {
|
||||
} else {
|
||||
assert.Equal(t, currentPeer.ExtraDNSLabels, loggedinPeer.ExtraDNSLabels, "ExtraDNSLabels mismatch on loggedinPeer")
|
||||
}
|
||||
assert.NotNil(t, network, "network should not be nil on success")
|
||||
assert.NotNil(t, networkMap, "networkMap should not be nil on success")
|
||||
|
||||
assert.Equal(t, existingAccountID, loggedinPeer.AccountID, "AccountID mismatch for logged peer")
|
||||
|
||||
@@ -1863,7 +1867,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
||||
peer4, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
}, false)
|
||||
@@ -1986,7 +1990,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
||||
peer4, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
LoginExpirationEnabled: true,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
@@ -2053,7 +2057,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
peer5, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
||||
peer5, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
LoginExpirationEnabled: true,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
@@ -2108,7 +2112,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
peer6, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser3", &nbpeer.Peer{
|
||||
peer6, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser3", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
LoginExpirationEnabled: true,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
@@ -2286,7 +2290,7 @@ func Test_AddPeer(t *testing.T) {
|
||||
|
||||
<-start
|
||||
|
||||
_, _, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", newPeer, false)
|
||||
_, _, _, err := manager.AddPeer(context.Background(), "", setupKey.Key, "", newPeer, false)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("AddPeer failed for peer %d: %w", i, err)
|
||||
return
|
||||
@@ -2366,7 +2370,7 @@ func TestAddPeer_UserPendingApprovalBlocked(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", pendingUser.Id, peer, false)
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", pendingUser.Id, peer, false)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "user pending approval cannot add peers")
|
||||
}
|
||||
@@ -2401,7 +2405,7 @@ func TestAddPeer_ApprovedUserCanAddPeers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, _, _, _, err = manager.AddPeer(context.Background(), "", "", regularUser.Id, peer, false)
|
||||
_, _, _, err = manager.AddPeer(context.Background(), "", "", regularUser.Id, peer, false)
|
||||
require.NoError(t, err, "Regular user should be able to add peers")
|
||||
}
|
||||
|
||||
@@ -2444,7 +2448,7 @@ func TestLoginPeer_UserPendingApprovalBlocked(t *testing.T) {
|
||||
WtVersion: "0.28.0",
|
||||
},
|
||||
}
|
||||
existingPeer, _, _, _, err := manager.AddPeer(context.Background(), "", "", pendingUser.Id, newPeer, false)
|
||||
existingPeer, _, _, err := manager.AddPeer(context.Background(), "", "", pendingUser.Id, newPeer, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Now set the user back to pending approval after peer was created
|
||||
@@ -2463,7 +2467,7 @@ func TestLoginPeer_UserPendingApprovalBlocked(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, _, _, _, err = manager.LoginPeer(context.Background(), login)
|
||||
_, _, _, err = manager.LoginPeer(context.Background(), login)
|
||||
require.Error(t, err)
|
||||
e, ok := status.FromError(err)
|
||||
require.True(t, ok, "error is not a gRPC status error")
|
||||
@@ -2500,7 +2504,7 @@ func TestLoginPeer_ApprovedUserCanLogin(t *testing.T) {
|
||||
WtVersion: "0.28.0",
|
||||
},
|
||||
}
|
||||
existingPeer, _, _, _, err := manager.AddPeer(context.Background(), "", "", regularUser.Id, newPeer, false)
|
||||
existingPeer, _, _, err := manager.AddPeer(context.Background(), "", "", regularUser.Id, newPeer, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to login with regular user
|
||||
@@ -2513,7 +2517,7 @@ func TestLoginPeer_ApprovedUserCanLogin(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, _, _, _, err = manager.LoginPeer(context.Background(), login)
|
||||
_, _, _, err = manager.LoginPeer(context.Background(), login)
|
||||
require.NoError(t, err, "Regular user should be able to login peers")
|
||||
}
|
||||
|
||||
@@ -2837,7 +2841,7 @@ func TestUpdatePeer_DnsLabelCollisionWithFQDN(t *testing.T) {
|
||||
// Add first peer with hostname that produces DNS label "netbird1"
|
||||
key1, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "netbird1.netbird.cloud"},
|
||||
}, false)
|
||||
@@ -2847,7 +2851,7 @@ func TestUpdatePeer_DnsLabelCollisionWithFQDN(t *testing.T) {
|
||||
// Add second peer with a different hostname
|
||||
key2, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer2, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "ip-10-29-5-130"},
|
||||
}, false)
|
||||
@@ -2871,7 +2875,7 @@ func TestUpdatePeer_DnsLabelUniqueName(t *testing.T) {
|
||||
|
||||
key1, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer1, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer1, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key1.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "web-server"},
|
||||
}, false)
|
||||
@@ -2881,7 +2885,7 @@ func TestUpdatePeer_DnsLabelUniqueName(t *testing.T) {
|
||||
// Add second peer and rename it to a unique FQDN whose first label doesn't collide
|
||||
key2, err := wgtypes.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
peer2, _, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
peer2, _, _, err := manager.AddPeer(context.Background(), "", "", userID, &nbpeer.Peer{
|
||||
Key: key2.PublicKey().String(),
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: "old-name"},
|
||||
}, false)
|
||||
|
||||
@@ -1156,47 +1156,6 @@ func policyRuleImpliesLegacySSH(rule *PolicyRule) bool {
|
||||
return rule.Protocol == PolicyRuleProtocolALL || (rule.Protocol == PolicyRuleProtocolTCP && (portsIncludesSSH(rule.Ports) || portRangeIncludesSSH(rule.PortRanges)))
|
||||
}
|
||||
|
||||
// PeerSSHEnabledFromPolicies is the network-map-free equivalent of the sshEnabled
|
||||
// determination in GetPeerConnectionResources / CalculateNetworkMapFromComponents.
|
||||
func PeerSSHEnabledFromPolicies(policies []*Policy, peerID string, peerGroupIDs map[string]struct{}, peerSSHEnabled bool) bool {
|
||||
for _, policy := range policies {
|
||||
if !policy.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, rule := range policy.Rules {
|
||||
if !rule.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
isSSHRule := rule.Protocol == PolicyRuleProtocolNetbirdSSH ||
|
||||
(policyRuleImpliesLegacySSH(rule) && peerSSHEnabled)
|
||||
if !isSSHRule {
|
||||
continue
|
||||
}
|
||||
|
||||
if ruleHasDestination(rule, peerID, peerGroupIDs) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleHasDestination(rule *PolicyRule, peerID string, peerGroupIDs map[string]struct{}) bool {
|
||||
if rule.DestinationResource.Type == ResourceTypePeer && rule.DestinationResource.ID != "" {
|
||||
return rule.DestinationResource.ID == peerID
|
||||
}
|
||||
|
||||
for _, groupID := range rule.Destinations {
|
||||
if _, ok := peerGroupIDs[groupID]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func portRangeIncludesSSH(portRanges []RulePortRange) bool {
|
||||
for _, pr := range portRanges {
|
||||
if (pr.Start <= defaultSSHPortNumber && pr.End >= defaultSSHPortNumber) || (pr.Start <= nativeSSHPortNumber && pr.End >= nativeSSHPortNumber) {
|
||||
|
||||
@@ -1233,97 +1233,3 @@ func TestComponents_DisabledRuleInEnabledPolicy(t *testing.T) {
|
||||
assert.True(t, has3000, "enabled rule should generate firewall rule for port 3000")
|
||||
assert.False(t, has3001, "disabled rule should NOT generate firewall rule for port 3001")
|
||||
}
|
||||
|
||||
func peerGroupIDSet(account *types.Account, peerID string) map[string]struct{} {
|
||||
return account.GetPeerGroups(peerID)
|
||||
}
|
||||
|
||||
func assertSSHEquivalence(t *testing.T, account *types.Account, peerID string, validatedPeers map[string]struct{}) {
|
||||
t.Helper()
|
||||
nm := componentsNetworkMap(account, peerID, validatedPeers)
|
||||
require.NotNil(t, nm)
|
||||
|
||||
got := types.PeerSSHEnabledFromPolicies(account.Policies, peerID, peerGroupIDSet(account, peerID), account.Peers[peerID].SSHEnabled)
|
||||
assert.Equalf(t, nm.EnableSSH, got, "PeerSSHEnabledFromPolicies mismatch for %s", peerID)
|
||||
}
|
||||
|
||||
func TestPeerSSHEnabledFromPolicies_MatchesMap_NetbirdSSHProtocol(t *testing.T) {
|
||||
account, validatedPeers := scalableTestAccount(20, 2)
|
||||
account.Groups["ssh-users"] = &types.Group{ID: "ssh-users", Name: "SSH Users", Peers: []string{}}
|
||||
account.Policies = append(account.Policies, &types.Policy{
|
||||
ID: "policy-ssh", Name: "SSH Access", Enabled: true, AccountID: "test-account",
|
||||
Rules: []*types.PolicyRule{{
|
||||
ID: "rule-ssh", Name: "Allow SSH", Enabled: true,
|
||||
Action: types.PolicyTrafficActionAccept, Protocol: types.PolicyRuleProtocolNetbirdSSH,
|
||||
Bidirectional: false,
|
||||
Sources: []string{"group-0"}, Destinations: []string{"group-1"},
|
||||
AuthorizedGroups: map[string][]string{"ssh-users": {"root"}},
|
||||
}},
|
||||
})
|
||||
|
||||
assertSSHEquivalence(t, account, "peer-10", validatedPeers)
|
||||
assertSSHEquivalence(t, account, "peer-0", validatedPeers)
|
||||
}
|
||||
|
||||
func TestPeerSSHEnabledFromPolicies_MatchesMap_NoSSHPolicy(t *testing.T) {
|
||||
account, validatedPeers := scalableTestAccount(20, 2)
|
||||
assertSSHEquivalence(t, account, "peer-0", validatedPeers)
|
||||
}
|
||||
|
||||
func TestPeerSSHEnabledFromPolicies_MatchesMap_LegacyImpliedSSH(t *testing.T) {
|
||||
account, validatedPeers := scalableTestAccount(20, 2)
|
||||
account.Peers["peer-10"].SSHEnabled = true
|
||||
assertSSHEquivalence(t, account, "peer-10", validatedPeers)
|
||||
assertSSHEquivalence(t, account, "peer-11", validatedPeers)
|
||||
}
|
||||
|
||||
func TestPeerSSHEnabledFromPolicies_MatchesMap_PeerAsDestinationResource(t *testing.T) {
|
||||
account, validatedPeers := scalableTestAccountWithoutDefaultPolicy(20, 2)
|
||||
account.Policies = append(account.Policies, &types.Policy{
|
||||
ID: "policy-ssh-res", Name: "SSH to peer", Enabled: true, AccountID: "test-account",
|
||||
Rules: []*types.PolicyRule{{
|
||||
ID: "rule-ssh-res", Name: "SSH to peer-5", Enabled: true,
|
||||
Action: types.PolicyTrafficActionAccept, Protocol: types.PolicyRuleProtocolNetbirdSSH,
|
||||
Sources: []string{"group-0"},
|
||||
DestinationResource: types.Resource{ID: "peer-5", Type: types.ResourceTypePeer},
|
||||
}},
|
||||
})
|
||||
|
||||
assertSSHEquivalence(t, account, "peer-5", validatedPeers)
|
||||
assertSSHEquivalence(t, account, "peer-6", validatedPeers)
|
||||
}
|
||||
|
||||
func TestPeerSSHEnabledFromPolicies_MatchesMap_DisabledSSHPolicy(t *testing.T) {
|
||||
account, validatedPeers := scalableTestAccountWithoutDefaultPolicy(20, 2)
|
||||
account.Policies = append(account.Policies, &types.Policy{
|
||||
ID: "policy-ssh-off", Name: "SSH disabled", Enabled: false, AccountID: "test-account",
|
||||
Rules: []*types.PolicyRule{{
|
||||
ID: "rule-ssh-off", Name: "Allow SSH", Enabled: true,
|
||||
Action: types.PolicyTrafficActionAccept, Protocol: types.PolicyRuleProtocolNetbirdSSH,
|
||||
Sources: []string{"group-0"}, Destinations: []string{"group-1"},
|
||||
}},
|
||||
})
|
||||
assertSSHEquivalence(t, account, "peer-10", validatedPeers)
|
||||
}
|
||||
|
||||
func TestPeerSSHEnabledFromPolicies_MatchesMap_Sweep(t *testing.T) {
|
||||
account, validatedPeers := scalableTestAccount(60, 6)
|
||||
account.Policies = append(account.Policies, &types.Policy{
|
||||
ID: "policy-ssh-sweep", Name: "SSH sweep", Enabled: true, AccountID: "test-account",
|
||||
Rules: []*types.PolicyRule{{
|
||||
ID: "rule-ssh-sweep", Name: "Allow SSH", Enabled: true,
|
||||
Action: types.PolicyTrafficActionAccept, Protocol: types.PolicyRuleProtocolNetbirdSSH,
|
||||
Sources: []string{"group-0"}, Destinations: []string{"group-2"},
|
||||
}},
|
||||
})
|
||||
for peerID := range account.Peers {
|
||||
account.Peers[peerID].SSHEnabled = len(peerID)%2 == 0
|
||||
}
|
||||
|
||||
for peerID := range account.Peers {
|
||||
if _, ok := validatedPeers[peerID]; !ok {
|
||||
continue
|
||||
}
|
||||
assertSSHEquivalence(t, account, peerID, validatedPeers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,9 @@ type Settings struct {
|
||||
// when false, updates require user interaction from the UI
|
||||
AutoUpdateAlways bool `gorm:"default:false"`
|
||||
|
||||
// MetricsPushEnabled globally enables or disables client metrics push for the account
|
||||
MetricsPushEnabled bool `gorm:"default:false"`
|
||||
|
||||
// IPv6EnabledGroups is the list of group IDs whose peers receive IPv6 overlay addresses.
|
||||
// Peers not in any of these groups will not be allocated an IPv6 address.
|
||||
// Empty list means IPv6 is disabled for the account.
|
||||
@@ -109,6 +112,7 @@ func (s *Settings) Copy() *Settings {
|
||||
NetworkRangeV6: s.NetworkRangeV6,
|
||||
AutoUpdateVersion: s.AutoUpdateVersion,
|
||||
AutoUpdateAlways: s.AutoUpdateAlways,
|
||||
MetricsPushEnabled: s.MetricsPushEnabled,
|
||||
IPv6EnabledGroups: slices.Clone(s.IPv6EnabledGroups),
|
||||
EmbeddedIdpEnabled: s.EmbeddedIdpEnabled,
|
||||
LocalAuthDisabled: s.LocalAuthDisabled,
|
||||
|
||||
@@ -1565,7 +1565,7 @@ func TestUserAccountPeersUpdate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedPeerKey := key.PublicKey().String()
|
||||
peer4, _, _, _, err := manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
||||
peer4, _, _, err := manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
|
||||
Key: expectedPeerKey,
|
||||
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
|
||||
}, false)
|
||||
|
||||
@@ -371,6 +371,10 @@ components:
|
||||
description: When true, updates are installed automatically in the background. When false, updates require user interaction from the UI.
|
||||
type: boolean
|
||||
example: false
|
||||
metrics_push_enabled:
|
||||
description: Enables or disables client metrics push for all peers in the account
|
||||
type: boolean
|
||||
example: false
|
||||
embedded_idp_enabled:
|
||||
description: Indicates whether the embedded identity provider (Dex) is enabled for this account. This is a read-only field.
|
||||
type: boolean
|
||||
|
||||
@@ -1510,6 +1510,9 @@ type AccountSettings struct {
|
||||
// LocalMfaEnabled Enables or disables TOTP multi-factor authentication for local users. Only applicable when the embedded identity provider is enabled.
|
||||
LocalMfaEnabled *bool `json:"local_mfa_enabled,omitempty"`
|
||||
|
||||
// MetricsPushEnabled Enables or disables client metrics push for all peers in the account
|
||||
MetricsPushEnabled *bool `json:"metrics_push_enabled,omitempty"`
|
||||
|
||||
// NetworkRange Allows to define a custom network range for the account in CIDR format
|
||||
NetworkRange *string `json:"network_range,omitempty"`
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -312,6 +312,8 @@ message NetbirdConfig {
|
||||
RelayConfig relay = 4;
|
||||
|
||||
FlowConfig flow = 5;
|
||||
|
||||
MetricsConfig metrics = 6;
|
||||
}
|
||||
|
||||
// HostConfig describes connection properties of some server (e.g. STUN, Signal, Management)
|
||||
@@ -350,6 +352,10 @@ message FlowConfig {
|
||||
bool dnsCollection = 8;
|
||||
}
|
||||
|
||||
message MetricsConfig {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
// JWTConfig represents JWT authentication configuration for validating tokens.
|
||||
message JWTConfig {
|
||||
string issuer = 1;
|
||||
|
||||
@@ -1532,7 +1532,7 @@ type SendStatusUpdateRequest struct {
|
||||
CertificateIssued bool `protobuf:"varint,4,opt,name=certificate_issued,json=certificateIssued,proto3" json:"certificate_issued,omitempty"`
|
||||
ErrorMessage *string `protobuf:"bytes,5,opt,name=error_message,json=errorMessage,proto3,oneof" json:"error_message,omitempty"`
|
||||
// Per-account inbound listener state for the account that owns
|
||||
// service_id. Populated only when --private-inbound is enabled and the
|
||||
// service_id. Populated only when --private is enabled and the
|
||||
// embedded client for the account is up. Field numbers >=50 reserved
|
||||
// for observability extensions.
|
||||
InboundListener *ProxyInboundListener `protobuf:"bytes,50,opt,name=inbound_listener,json=inboundListener,proto3,oneof" json:"inbound_listener,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user