NetBird SSH (#361)

This PR adds support for SSH access through the NetBird network
without managing SSH skeys.
NetBird client app has an embedded SSH server (Linux/Mac only) 
and a netbird ssh command.
This commit is contained in:
Misha Bragin
2022-06-23 17:04:53 +02:00
committed by GitHub
parent f883a10535
commit 06860c4c10
32 changed files with 1702 additions and 349 deletions

View File

@@ -51,6 +51,7 @@ type AccountManager interface {
GetNetworkMap(peerKey string) (*NetworkMap, error)
AddPeer(setupKey string, userId string, peer *Peer) (*Peer, error)
UpdatePeerMeta(peerKey string, meta PeerSystemMeta) error
UpdatePeerSSHKey(peerKey string, sshKey string) error
GetUsersFromAccount(accountId string) ([]*UserInfo, error)
GetGroup(accountId, groupID string) (*Group, error)
SaveGroup(accountId string, group *Group) error
@@ -65,6 +66,7 @@ type AccountManager interface {
UpdateRule(accountID string, ruleID string, operations []RuleUpdateOperation) (*Rule, error)
DeleteRule(accountId, ruleID string) error
ListRules(accountId string) ([]*Rule, error)
UpdatePeer(accountID string, peer *Peer) (*Peer, error)
}
type DefaultAccountManager struct {

View File

@@ -185,9 +185,15 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
return nil, status.Errorf(codes.InvalidArgument, "peer meta data was not provided")
}
var sshKey []byte
if req.GetPeerKeys() != nil {
sshKey = req.GetPeerKeys().GetSshPubKey()
}
peer, err := s.accountManager.AddPeer(reqSetupKey, userId, &Peer{
Key: peerKey.String(),
Name: meta.GetHostname(),
Key: peerKey.String(),
Name: meta.GetHostname(),
SSHKey: string(sshKey),
Meta: PeerSystemMeta{
Hostname: meta.GetHostname(),
GoOS: meta.GetGoOS(),
@@ -290,6 +296,19 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
return nil, status.Error(codes.Internal, "internal server error")
}
}
var sshKey []byte
if loginReq.GetPeerKeys() != nil {
sshKey = loginReq.GetPeerKeys().GetSshPubKey()
}
if len(sshKey) > 0 {
err = s.accountManager.UpdatePeerSSHKey(peerKey.String(), string(sshKey))
if err != nil {
return nil, err
}
}
// if peer has reached this point then it has logged in
loginResp := &proto.LoginResponse{
WiretrusteeConfig: toWiretrusteeConfig(s.config, nil),
@@ -365,7 +384,8 @@ func toWiretrusteeConfig(config *Config, turnCredentials *TURNCredentials) *prot
func toPeerConfig(peer *Peer) *proto.PeerConfig {
return &proto.PeerConfig{
Address: fmt.Sprintf("%s/%d", peer.IP.String(), SubnetSize), // take it from the network
Address: fmt.Sprintf("%s/%d", peer.IP.String(), SubnetSize), // take it from the network
SshConfig: &proto.SSHConfig{SshEnabled: peer.SSHEnabled},
}
}
@@ -375,9 +395,9 @@ func toRemotePeerConfig(peers []*Peer) []*proto.RemotePeerConfig {
remotePeers = append(remotePeers, &proto.RemotePeerConfig{
WgPubKey: rPeer.Key,
AllowedIps: []string{fmt.Sprintf(AllowedIPsFormat, rPeer.IP)},
SshConfig: &proto.SSHConfig{SshPubKey: []byte(rPeer.SSHKey)},
})
}
return remotePeers
}

View File

@@ -85,6 +85,9 @@ components:
required:
- type
- value
ssh_enabled:
description: Indicates whether SSH server is enabled on this peer
type: boolean
required:
- ip
- connected
@@ -93,6 +96,7 @@ components:
- version
- groups
- activated_by
- ssh_enabled
SetupKey:
type: object
properties:
@@ -397,8 +401,11 @@ paths:
properties:
name:
type: string
ssh_enabled:
type: boolean
required:
- name
- ssh_enabled
responses:
'200':
description: A Peer object

View File

@@ -115,6 +115,9 @@ type Peer struct {
// Peer's operating system and version
Os string `json:"os"`
// Indicates whether SSH server is enabled on this peer
SshEnabled bool `json:"ssh_enabled"`
// Peer's daemon or cli version
Version string `json:"version"`
}
@@ -265,7 +268,8 @@ type PutApiGroupsIdJSONBody struct {
// PutApiPeersIdJSONBody defines parameters for PutApiPeersId.
type PutApiPeersIdJSONBody struct {
Name string `json:"name"`
Name string `json:"name"`
SshEnabled bool `json:"ssh_enabled"`
}
// PostApiRulesJSONBody defines parameters for PostApiRules.

View File

@@ -34,7 +34,9 @@ func (h *Peers) updatePeer(account *server.Account, peer *server.Peer, w http.Re
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
peer, err = h.accountManager.RenamePeer(account.Id, peer.Key, req.Name)
update := &server.Peer{Key: peer.Key, SSHEnabled: req.SshEnabled, Name: req.Name}
peer, err = h.accountManager.UpdatePeer(account.Id, update)
if err != nil {
log.Errorf("failed updating peer %s under account %s %v", peerIp, account.Id, err)
http.Redirect(w, r, "/", http.StatusInternalServerError)
@@ -133,13 +135,14 @@ func toPeerResponse(peer *server.Peer, account *server.Account) *api.Peer {
}
}
return &api.Peer{
Id: peer.IP.String(),
Name: peer.Name,
Ip: peer.IP.String(),
Connected: peer.Status.Connected,
LastSeen: peer.Status.LastSeen,
Os: fmt.Sprintf("%s %s", peer.Meta.OS, peer.Meta.Core),
Version: peer.Meta.WtVersion,
Groups: groupsInfo,
Id: peer.IP.String(),
Name: peer.Name,
Ip: peer.IP.String(),
Connected: peer.Status.Connected,
LastSeen: peer.Status.LastSeen,
Os: fmt.Sprintf("%s %s", peer.Meta.OS, peer.Meta.Core),
Version: peer.Meta.WtVersion,
Groups: groupsInfo,
SshEnabled: peer.SSHEnabled,
}
}

View File

@@ -41,6 +41,8 @@ type MockAccountManager struct {
ListRulesFunc func(accountID string) ([]*server.Rule, error)
GetUsersFromAccountFunc func(accountID string) ([]*server.UserInfo, error)
UpdatePeerMetaFunc func(peerKey string, meta server.PeerSystemMeta) error
UpdatePeerSSHKeyFunc func(peerKey string, sshKey string) error
UpdatePeerFunc func(accountID string, peer *server.Peer) (*server.Peer, error)
}
// GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface
@@ -48,7 +50,7 @@ func (am *MockAccountManager) GetUsersFromAccount(accountID string) ([]*server.U
if am.GetUsersFromAccountFunc != nil {
return am.GetUsersFromAccountFunc(accountID)
}
return nil, status.Errorf(codes.Unimplemented, "method GetUsersFromAccount not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetUsersFromAccount is not implemented")
}
// GetOrCreateAccountByUser mock implementation of GetOrCreateAccountByUser from server.AccountManager interface
@@ -60,7 +62,7 @@ func (am *MockAccountManager) GetOrCreateAccountByUser(
}
return nil, status.Errorf(
codes.Unimplemented,
"method GetOrCreateAccountByUser not implemented",
"method GetOrCreateAccountByUser is not implemented",
)
}
@@ -69,7 +71,7 @@ func (am *MockAccountManager) GetAccountByUser(userId string) (*server.Account,
if am.GetAccountByUserFunc != nil {
return am.GetAccountByUserFunc(userId)
}
return nil, status.Errorf(codes.Unimplemented, "method GetAccountByUser not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAccountByUser is not implemented")
}
// AddSetupKey mock implementation of AddSetupKey from server.AccountManager interface
@@ -82,7 +84,7 @@ func (am *MockAccountManager) AddSetupKey(
if am.AddSetupKeyFunc != nil {
return am.AddSetupKeyFunc(accountId, keyName, keyType, expiresIn)
}
return nil, status.Errorf(codes.Unimplemented, "method AddSetupKey not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AddSetupKey is not implemented")
}
// RevokeSetupKey mock implementation of RevokeSetupKey from server.AccountManager interface
@@ -93,7 +95,7 @@ func (am *MockAccountManager) RevokeSetupKey(
if am.RevokeSetupKeyFunc != nil {
return am.RevokeSetupKeyFunc(accountId, keyId)
}
return nil, status.Errorf(codes.Unimplemented, "method RevokeSetupKey not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RevokeSetupKey is not implemented")
}
// RenameSetupKey mock implementation of RenameSetupKey from server.AccountManager interface
@@ -105,7 +107,7 @@ func (am *MockAccountManager) RenameSetupKey(
if am.RenameSetupKeyFunc != nil {
return am.RenameSetupKeyFunc(accountId, keyId, newName)
}
return nil, status.Errorf(codes.Unimplemented, "method RenameSetupKey not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RenameSetupKey is not implemented")
}
// GetAccountById mock implementation of GetAccountById from server.AccountManager interface
@@ -113,7 +115,7 @@ func (am *MockAccountManager) GetAccountById(accountId string) (*server.Account,
if am.GetAccountByIdFunc != nil {
return am.GetAccountByIdFunc(accountId)
}
return nil, status.Errorf(codes.Unimplemented, "method GetAccountById not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetAccountById is not implemented")
}
// GetAccountByUserOrAccountId mock implementation of GetAccountByUserOrAccountId from server.AccountManager interface
@@ -125,7 +127,7 @@ func (am *MockAccountManager) GetAccountByUserOrAccountId(
}
return nil, status.Errorf(
codes.Unimplemented,
"method GetAccountByUserOrAccountId not implemented",
"method GetAccountByUserOrAccountId is not implemented",
)
}
@@ -138,7 +140,7 @@ func (am *MockAccountManager) GetAccountWithAuthorizationClaims(
}
return nil, status.Errorf(
codes.Unimplemented,
"method GetAccountWithAuthorizationClaims not implemented",
"method GetAccountWithAuthorizationClaims is not implemented",
)
}
@@ -147,7 +149,7 @@ func (am *MockAccountManager) AccountExists(accountId string) (*bool, error) {
if am.AccountExistsFunc != nil {
return am.AccountExistsFunc(accountId)
}
return nil, status.Errorf(codes.Unimplemented, "method AccountExists not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AccountExists is not implemented")
}
// GetPeer mock implementation of GetPeer from server.AccountManager interface
@@ -155,7 +157,7 @@ func (am *MockAccountManager) GetPeer(peerKey string) (*server.Peer, error) {
if am.GetPeerFunc != nil {
return am.GetPeerFunc(peerKey)
}
return nil, status.Errorf(codes.Unimplemented, "method GetPeer not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetPeer is not implemented")
}
// MarkPeerConnected mock implementation of MarkPeerConnected from server.AccountManager interface
@@ -163,7 +165,7 @@ func (am *MockAccountManager) MarkPeerConnected(peerKey string, connected bool)
if am.MarkPeerConnectedFunc != nil {
return am.MarkPeerConnectedFunc(peerKey, connected)
}
return status.Errorf(codes.Unimplemented, "method MarkPeerConnected not implemented")
return status.Errorf(codes.Unimplemented, "method MarkPeerConnected is not implemented")
}
// RenamePeer mock implementation of RenamePeer from server.AccountManager interface
@@ -175,7 +177,7 @@ func (am *MockAccountManager) RenamePeer(
if am.RenamePeerFunc != nil {
return am.RenamePeerFunc(accountId, peerKey, newName)
}
return nil, status.Errorf(codes.Unimplemented, "method RenamePeer not implemented")
return nil, status.Errorf(codes.Unimplemented, "method RenamePeer is not implemented")
}
// DeletePeer mock implementation of DeletePeer from server.AccountManager interface
@@ -183,7 +185,7 @@ func (am *MockAccountManager) DeletePeer(accountId string, peerKey string) (*ser
if am.DeletePeerFunc != nil {
return am.DeletePeerFunc(accountId, peerKey)
}
return nil, status.Errorf(codes.Unimplemented, "method DeletePeer not implemented")
return nil, status.Errorf(codes.Unimplemented, "method DeletePeer is not implemented")
}
// GetPeerByIP mock implementation of GetPeerByIP from server.AccountManager interface
@@ -191,7 +193,7 @@ func (am *MockAccountManager) GetPeerByIP(accountId string, peerIP string) (*ser
if am.GetPeerByIPFunc != nil {
return am.GetPeerByIPFunc(accountId, peerIP)
}
return nil, status.Errorf(codes.Unimplemented, "method GetPeerByIP not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetPeerByIP is not implemented")
}
// GetNetworkMap mock implementation of GetNetworkMap from server.AccountManager interface
@@ -199,7 +201,7 @@ func (am *MockAccountManager) GetNetworkMap(peerKey string) (*server.NetworkMap,
if am.GetNetworkMapFunc != nil {
return am.GetNetworkMapFunc(peerKey)
}
return nil, status.Errorf(codes.Unimplemented, "method GetNetworkMap not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetNetworkMap is not implemented")
}
// AddPeer mock implementation of AddPeer from server.AccountManager interface
@@ -211,7 +213,7 @@ func (am *MockAccountManager) AddPeer(
if am.AddPeerFunc != nil {
return am.AddPeerFunc(setupKey, userId, peer)
}
return nil, status.Errorf(codes.Unimplemented, "method AddPeer not implemented")
return nil, status.Errorf(codes.Unimplemented, "method AddPeer is not implemented")
}
// GetGroup mock implementation of GetGroup from server.AccountManager interface
@@ -219,7 +221,7 @@ func (am *MockAccountManager) GetGroup(accountID, groupID string) (*server.Group
if am.GetGroupFunc != nil {
return am.GetGroupFunc(accountID, groupID)
}
return nil, status.Errorf(codes.Unimplemented, "method GetGroup not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetGroup is not implemented")
}
// SaveGroup mock implementation of SaveGroup from server.AccountManager interface
@@ -227,7 +229,7 @@ func (am *MockAccountManager) SaveGroup(accountID string, group *server.Group) e
if am.SaveGroupFunc != nil {
return am.SaveGroupFunc(accountID, group)
}
return status.Errorf(codes.Unimplemented, "method SaveGroup not implemented")
return status.Errorf(codes.Unimplemented, "method SaveGroup is not implemented")
}
// UpdateGroup mock implementation of UpdateGroup from server.AccountManager interface
@@ -243,7 +245,7 @@ func (am *MockAccountManager) DeleteGroup(accountID, groupID string) error {
if am.DeleteGroupFunc != nil {
return am.DeleteGroupFunc(accountID, groupID)
}
return status.Errorf(codes.Unimplemented, "method DeleteGroup not implemented")
return status.Errorf(codes.Unimplemented, "method DeleteGroup is not implemented")
}
// ListGroups mock implementation of ListGroups from server.AccountManager interface
@@ -251,7 +253,7 @@ func (am *MockAccountManager) ListGroups(accountID string) ([]*server.Group, err
if am.ListGroupsFunc != nil {
return am.ListGroupsFunc(accountID)
}
return nil, status.Errorf(codes.Unimplemented, "method ListGroups not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListGroups is not implemented")
}
// GroupAddPeer mock implementation of GroupAddPeer from server.AccountManager interface
@@ -259,7 +261,7 @@ func (am *MockAccountManager) GroupAddPeer(accountID, groupID, peerKey string) e
if am.GroupAddPeerFunc != nil {
return am.GroupAddPeerFunc(accountID, groupID, peerKey)
}
return status.Errorf(codes.Unimplemented, "method GroupAddPeer not implemented")
return status.Errorf(codes.Unimplemented, "method GroupAddPeer is not implemented")
}
// GroupDeletePeer mock implementation of GroupDeletePeer from server.AccountManager interface
@@ -267,7 +269,7 @@ func (am *MockAccountManager) GroupDeletePeer(accountID, groupID, peerKey string
if am.GroupDeletePeerFunc != nil {
return am.GroupDeletePeerFunc(accountID, groupID, peerKey)
}
return status.Errorf(codes.Unimplemented, "method GroupDeletePeer not implemented")
return status.Errorf(codes.Unimplemented, "method GroupDeletePeer is not implemented")
}
// GroupListPeers mock implementation of GroupListPeers from server.AccountManager interface
@@ -275,7 +277,7 @@ func (am *MockAccountManager) GroupListPeers(accountID, groupID string) ([]*serv
if am.GroupListPeersFunc != nil {
return am.GroupListPeersFunc(accountID, groupID)
}
return nil, status.Errorf(codes.Unimplemented, "method GroupListPeers not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GroupListPeers is not implemented")
}
// GetRule mock implementation of GetRule from server.AccountManager interface
@@ -283,7 +285,7 @@ func (am *MockAccountManager) GetRule(accountID, ruleID string) (*server.Rule, e
if am.GetRuleFunc != nil {
return am.GetRuleFunc(accountID, ruleID)
}
return nil, status.Errorf(codes.Unimplemented, "method GetRule not implemented")
return nil, status.Errorf(codes.Unimplemented, "method GetRule is not implemented")
}
// SaveRule mock implementation of SaveRule from server.AccountManager interface
@@ -291,7 +293,7 @@ func (am *MockAccountManager) SaveRule(accountID string, rule *server.Rule) erro
if am.SaveRuleFunc != nil {
return am.SaveRuleFunc(accountID, rule)
}
return status.Errorf(codes.Unimplemented, "method SaveRule not implemented")
return status.Errorf(codes.Unimplemented, "method SaveRule is not implemented")
}
// UpdateRule mock implementation of UpdateRule from server.AccountManager interface
@@ -307,7 +309,7 @@ func (am *MockAccountManager) DeleteRule(accountID, ruleID string) error {
if am.DeleteRuleFunc != nil {
return am.DeleteRuleFunc(accountID, ruleID)
}
return status.Errorf(codes.Unimplemented, "method DeleteRule not implemented")
return status.Errorf(codes.Unimplemented, "method DeleteRule is not implemented")
}
// ListRules mock implementation of ListRules from server.AccountManager interface
@@ -315,7 +317,7 @@ func (am *MockAccountManager) ListRules(accountID string) ([]*server.Rule, error
if am.ListRulesFunc != nil {
return am.ListRulesFunc(accountID)
}
return nil, status.Errorf(codes.Unimplemented, "method ListRules not implemented")
return nil, status.Errorf(codes.Unimplemented, "method ListRules is not implemented")
}
// UpdatePeerMeta mock implementation of UpdatePeerMeta from server.AccountManager interface
@@ -323,7 +325,7 @@ func (am *MockAccountManager) UpdatePeerMeta(peerKey string, meta server.PeerSys
if am.UpdatePeerMetaFunc != nil {
return am.UpdatePeerMetaFunc(peerKey, meta)
}
return status.Errorf(codes.Unimplemented, "method UpdatePeerMetaFunc not implemented")
return status.Errorf(codes.Unimplemented, "method UpdatePeerMetaFunc is not implemented")
}
// IsUserAdmin mock implementation of IsUserAdmin from server.AccountManager interface
@@ -331,5 +333,21 @@ func (am *MockAccountManager) IsUserAdmin(claims jwtclaims.AuthorizationClaims)
if am.IsUserAdminFunc != nil {
return am.IsUserAdminFunc(claims)
}
return false, status.Errorf(codes.Unimplemented, "method IsUserAdmin not implemented")
return false, status.Errorf(codes.Unimplemented, "method IsUserAdmin is not implemented")
}
// UpdatePeerSSHKey mocks UpdatePeerSSHKey function of the account manager
func (am *MockAccountManager) UpdatePeerSSHKey(peerKey string, sshKey string) error {
if am.UpdatePeerSSHKeyFunc != nil {
return am.UpdatePeerSSHKeyFunc(peerKey, sshKey)
}
return status.Errorf(codes.Unimplemented, "method UpdatePeerSSHKey is is not implemented")
}
// UpdatePeer mocks UpdatePeerFunc function of the account manager
func (am *MockAccountManager) UpdatePeer(accountID string, peer *server.Peer) (*server.Peer, error) {
if am.UpdatePeerFunc != nil {
return am.UpdatePeerFunc(accountID, peer)
}
return nil, status.Errorf(codes.Unimplemented, "method UpdatePeerFunc is is not implemented")
}

View File

@@ -47,18 +47,24 @@ type Peer struct {
Status *PeerStatus
// The user ID that registered the peer
UserID string
// SSHKey is a public SSH key of the peer
SSHKey string
// SSHEnabled indicated whether SSH server is enabled on the peer
SSHEnabled bool
}
// Copy copies Peer object
func (p *Peer) Copy() *Peer {
return &Peer{
Key: p.Key,
SetupKey: p.SetupKey,
IP: p.IP,
Meta: p.Meta,
Name: p.Name,
Status: p.Status,
UserID: p.UserID,
Key: p.Key,
SetupKey: p.SetupKey,
IP: p.IP,
Meta: p.Meta,
Name: p.Name,
Status: p.Status,
UserID: p.UserID,
SSHKey: p.SSHKey,
SSHEnabled: p.SSHEnabled,
}
}
@@ -100,6 +106,41 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerKey string, connected boo
return nil
}
// UpdatePeer updates peer. Only Peer.Name and Peer.SSHEnabled can be updated.
func (am *DefaultAccountManager) UpdatePeer(accountID string, update *Peer) (*Peer, error) {
am.mux.Lock()
defer am.mux.Unlock()
account, err := am.Store.GetAccount(accountID)
if err != nil {
return nil, status.Errorf(codes.NotFound, "account not found")
}
peer, err := am.Store.GetPeer(update.Key)
if err != nil {
return nil, err
}
peerCopy := peer.Copy()
if peer.Name != "" {
peerCopy.Name = update.Name
}
peerCopy.SSHEnabled = update.SSHEnabled
err = am.Store.SavePeer(accountID, peerCopy)
if err != nil {
return nil, err
}
err = am.updateAccountPeers(account)
if err != nil {
return nil, err
}
return peerCopy, nil
}
// RenamePeer changes peer's name
func (am *DefaultAccountManager) RenamePeer(
accountId string,
@@ -285,13 +326,15 @@ func (am *DefaultAccountManager) AddPeer(
}
newPeer := &Peer{
Key: peer.Key,
SetupKey: upperKey,
IP: nextIp,
Meta: peer.Meta,
Name: peer.Name,
UserID: userID,
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
Key: peer.Key,
SetupKey: upperKey,
IP: nextIp,
Meta: peer.Meta,
Name: peer.Name,
UserID: userID,
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
SSHEnabled: false,
SSHKey: peer.SSHKey,
}
// add peer to 'All' group
@@ -315,6 +358,38 @@ func (am *DefaultAccountManager) AddPeer(
return newPeer, nil
}
// UpdatePeerSSHKey updates peer's public SSH key
func (am *DefaultAccountManager) UpdatePeerSSHKey(peerKey string, sshKey string) error {
am.mux.Lock()
defer am.mux.Unlock()
if sshKey == "" {
log.Debugf("empty SSH key provided for peer %s, skipping update", peerKey)
return nil
}
peer, err := am.Store.GetPeer(peerKey)
if err != nil {
return err
}
account, err := am.Store.GetPeerAccount(peerKey)
if err != nil {
return err
}
peerCopy := peer.Copy()
peerCopy.SSHKey = sshKey
err = am.Store.SavePeer(account.Id, peerCopy)
if err != nil {
return err
}
// trigger network map update
return am.updateAccountPeers(account)
}
// UpdatePeerMeta updates peer's system metadata
func (am *DefaultAccountManager) UpdatePeerMeta(peerKey string, meta PeerSystemMeta) error {
am.mux.Lock()
@@ -345,7 +420,7 @@ func (am *DefaultAccountManager) UpdatePeerMeta(peerKey string, meta PeerSystemM
return nil
}
// getPeersByACL allowed for given peer by ACL
// getPeersByACL returns all peers that given peer has access to.
func (am *DefaultAccountManager) getPeersByACL(account *Account, peerKey string) []*Peer {
var peers []*Peer
srcRules, err := am.Store.GetPeerSrcRules(account.Id, peerKey)
@@ -409,7 +484,8 @@ func (am *DefaultAccountManager) getPeersByACL(account *Account, peerKey string)
return peers
}
// updateAccountPeers network map constructed by ACL
// updateAccountPeers updates all peers that belong to an account.
// Should be called when changes have to be synced to peers.
func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
// notify other peers of the change
peers, err := am.Store.GetAccountPeers(account.Id)
@@ -422,7 +498,7 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
err = am.peersUpdateManager.SendUpdate(p.Key,
&UpdateMessage{
Update: &proto.SyncResponse{
// fill those field for backward compatibility
// fill deprecated fields for backward compatibility
RemotePeers: update,
RemotePeersIsEmpty: len(update) == 0,
// new field
@@ -430,6 +506,7 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
Serial: account.Network.CurrentSerial(),
RemotePeers: update,
RemotePeersIsEmpty: len(update) == 0,
PeerConfig: toPeerConfig(p),
},
},
})

View File

@@ -9,6 +9,7 @@ import (
type UpdateMessage struct {
Update *proto.SyncResponse
}
type PeersUpdateManager struct {
peerChannels map[string]chan *UpdateMessage
channelsMux *sync.Mutex