2021-08-20 15:18:29 +02:00
package server
import (
2022-11-07 17:37:28 +01:00
"fmt"
nbdns "github.com/netbirdio/netbird/dns"
2023-01-02 15:11:32 +01:00
"github.com/netbirdio/netbird/management/server/activity"
2022-11-07 12:10:56 +01:00
"github.com/netbirdio/netbird/route"
2022-05-05 08:58:34 +02:00
"net"
2022-11-07 17:37:28 +01:00
"reflect"
2022-06-04 22:02:22 +02:00
"sync"
2022-05-05 08:58:34 +02:00
"testing"
2023-01-24 10:17:24 +01:00
"time"
2022-05-05 08:58:34 +02:00
2022-03-26 12:08:54 +01:00
"github.com/netbirdio/netbird/management/server/jwtclaims"
2022-05-05 08:58:34 +02:00
"github.com/stretchr/testify/assert"
2022-03-01 15:22:18 +01:00
"github.com/stretchr/testify/require"
2021-08-20 15:44:18 +02:00
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
2021-08-20 15:18:29 +02:00
)
2022-06-09 13:14:34 +02:00
func verifyCanAddPeerToAccount ( t * testing . T , manager AccountManager , account * Account , userID string ) {
peer := & Peer {
Key : "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8=" ,
Name : "test-host@netbird.io" ,
Meta : PeerSystemMeta {
Hostname : "test-host@netbird.io" ,
GoOS : "linux" ,
Kernel : "Linux" ,
Core : "21.04" ,
Platform : "x86_64" ,
OS : "Ubuntu" ,
WtVersion : "development" ,
UIVersion : "development" ,
} ,
}
var setupKey string
for _ , key := range account . SetupKeys {
setupKey = key . Key
}
_ , err := manager . AddPeer ( setupKey , userID , peer )
if err != nil {
t . Error ( "expected to add new peer successfully after creating new account, but failed" , err )
}
}
func verifyNewAccountHasDefaultFields ( t * testing . T , account * Account , createdBy string , domain string , expectedUsers [ ] string ) {
if len ( account . Peers ) != 0 {
t . Errorf ( "expected account to have len(Peers) = %v, got %v" , 0 , len ( account . Peers ) )
}
if len ( account . SetupKeys ) != 2 {
t . Errorf ( "expected account to have len(SetupKeys) = %v, got %v" , 2 , len ( account . SetupKeys ) )
}
ipNet := net . IPNet { IP : net . ParseIP ( "100.64.0.0" ) , Mask : net . IPMask { 255 , 192 , 0 , 0 } }
if ! ipNet . Contains ( account . Network . Net . IP ) {
t . Errorf ( "expected account's Network to be a subnet of %v, got %v" , ipNet . String ( ) , account . Network . Net . String ( ) )
}
g , err := account . GetGroupAll ( )
if err != nil {
t . Fatal ( err )
}
if g . Name != "All" {
t . Errorf ( "expecting account to have group ALL added by default" )
}
if len ( account . Users ) != len ( expectedUsers ) {
t . Errorf ( "expecting account to have %d users, got %d" , len ( expectedUsers ) , len ( account . Users ) )
}
if account . Users [ createdBy ] == nil {
t . Errorf ( "expecting account to have createdBy user %s in a user map " , createdBy )
}
for _ , expectedUserID := range expectedUsers {
if account . Users [ expectedUserID ] == nil {
t . Errorf ( "expecting account to have a user %s in a user map" , expectedUserID )
}
}
if account . CreatedBy != createdBy {
t . Errorf ( "expecting newly created account to be created by user %s, got %s" , createdBy , account . CreatedBy )
}
if account . Domain != domain {
t . Errorf ( "expecting newly created account to have domain %s, got %s" , domain , account . Domain )
}
if len ( account . Rules ) != 1 {
t . Errorf ( "expecting newly created account to have 1 rule, got %d" , len ( account . Rules ) )
}
for _ , rule := range account . Rules {
if rule . Name != "Default" {
t . Errorf ( "expecting newly created account to have Default rule, got %s" , rule . Name )
}
}
}
func TestNewAccount ( t * testing . T ) {
domain := "netbird.io"
userId := "account_creator"
2022-06-20 18:20:43 +02:00
accountID := "account_id"
account := newAccountWithId ( accountID , userId , domain )
2022-06-09 13:14:34 +02:00
verifyNewAccountHasDefaultFields ( t , account , userId , domain , [ ] string { userId } )
}
2021-12-27 13:17:15 +01:00
func TestAccountManager_GetOrCreateAccountByUser ( t * testing . T ) {
2021-08-20 15:44:18 +02:00
manager , err := createManager ( t )
2021-08-20 15:18:29 +02:00
if err != nil {
t . Fatal ( err )
2021-08-20 15:44:18 +02:00
return
2021-08-20 15:18:29 +02:00
}
2023-01-02 15:11:32 +01:00
account , err := manager . GetOrCreateAccountByUser ( userID , "" )
2021-08-20 15:18:29 +02:00
if err != nil {
t . Fatal ( err )
}
2021-12-27 13:17:15 +01:00
if account == nil {
2023-01-02 15:11:32 +01:00
t . Fatalf ( "expected to create an account for a user %s" , userID )
return
2021-08-20 15:18:29 +02:00
}
2023-01-02 15:11:32 +01:00
account , err = manager . Store . GetAccountByUser ( userID )
2021-12-27 13:17:15 +01:00
if err != nil {
2023-01-02 15:11:32 +01:00
t . Errorf ( "expected to get existing account after creation, no account was found for a user %s" , userID )
return
2021-08-20 15:18:29 +02:00
}
2023-01-02 15:11:32 +01:00
if account != nil && account . Users [ userID ] == nil {
t . Fatalf ( "expected to create an account for a user %s but no user was found after creation udner the account %s" , userID , account . Id )
return
}
// check the corresponding events that should have been generated
2023-01-24 10:17:24 +01:00
ev := getEvent ( t , account . Id , manager , activity . AccountCreated )
2023-01-02 15:11:32 +01:00
assert . NotNil ( t , ev )
assert . Equal ( t , account . Id , ev . AccountID )
assert . Equal ( t , userID , ev . InitiatorID )
assert . Equal ( t , account . Id , ev . TargetID )
2022-03-01 15:22:18 +01:00
}
2022-10-13 18:26:31 +02:00
func TestDefaultAccountManager_GetAccountFromToken ( t * testing . T ) {
2022-03-01 15:22:18 +01:00
type initUserParams jwtclaims . AuthorizationClaims
type test struct {
2022-03-10 13:47:36 +01:00
name string
inputClaims jwtclaims . AuthorizationClaims
inputInitUserParams initUserParams
inputUpdateAttrs bool
inputUpdateClaimAccount bool
testingFunc require . ComparisonAssertionFunc
expectedMSG string
expectedUserRole UserRole
expectedDomainCategory string
2022-09-29 10:51:18 +02:00
expectedDomain string
2022-03-10 13:47:36 +01:00
expectedPrimaryDomainStatus bool
2022-06-09 13:14:34 +02:00
expectedCreatedBy string
expectedUsers [ ] string
2022-03-01 15:22:18 +01:00
}
var (
publicDomain = "public.com"
privateDomain = "private.com"
unknownDomain = "unknown.com"
)
defaultInitAccount := initUserParams {
Domain : publicDomain ,
UserId : "defaultUser" ,
}
testCase1 := test {
name : "New User With Public Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : publicDomain ,
UserId : "pub-domain-user" ,
DomainCategory : PublicCategory ,
} ,
2022-03-10 13:47:36 +01:00
inputInitUserParams : defaultInitAccount ,
testingFunc : require . NotEqual ,
expectedMSG : "account IDs shouldn't match" ,
expectedUserRole : UserRoleAdmin ,
expectedDomainCategory : "" ,
2022-09-29 10:51:18 +02:00
expectedDomain : publicDomain ,
2022-03-10 13:47:36 +01:00
expectedPrimaryDomainStatus : false ,
2022-06-09 13:14:34 +02:00
expectedCreatedBy : "pub-domain-user" ,
expectedUsers : [ ] string { "pub-domain-user" } ,
2022-03-01 15:22:18 +01:00
}
initUnknown := defaultInitAccount
initUnknown . DomainCategory = UnknownCategory
initUnknown . Domain = unknownDomain
testCase2 := test {
name : "New User With Unknown Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : unknownDomain ,
UserId : "unknown-domain-user" ,
DomainCategory : UnknownCategory ,
} ,
2022-03-10 13:47:36 +01:00
inputInitUserParams : initUnknown ,
testingFunc : require . NotEqual ,
expectedMSG : "account IDs shouldn't match" ,
expectedUserRole : UserRoleAdmin ,
2022-09-29 10:51:18 +02:00
expectedDomain : unknownDomain ,
2022-03-10 13:47:36 +01:00
expectedDomainCategory : "" ,
expectedPrimaryDomainStatus : false ,
2022-06-09 13:14:34 +02:00
expectedCreatedBy : "unknown-domain-user" ,
expectedUsers : [ ] string { "unknown-domain-user" } ,
2022-03-01 15:22:18 +01:00
}
testCase3 := test {
name : "New User With Private Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : privateDomain ,
UserId : "pvt-domain-user" ,
DomainCategory : PrivateCategory ,
} ,
2022-03-10 13:47:36 +01:00
inputInitUserParams : defaultInitAccount ,
testingFunc : require . NotEqual ,
expectedMSG : "account IDs shouldn't match" ,
expectedUserRole : UserRoleAdmin ,
2022-09-29 10:51:18 +02:00
expectedDomain : privateDomain ,
2022-03-10 13:47:36 +01:00
expectedDomainCategory : PrivateCategory ,
expectedPrimaryDomainStatus : true ,
2022-06-09 13:14:34 +02:00
expectedCreatedBy : "pvt-domain-user" ,
expectedUsers : [ ] string { "pvt-domain-user" } ,
2022-03-01 15:22:18 +01:00
}
privateInitAccount := defaultInitAccount
privateInitAccount . Domain = privateDomain
privateInitAccount . DomainCategory = PrivateCategory
testCase4 := test {
name : "New Regular User With Existing Private Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : privateDomain ,
2022-06-09 13:14:34 +02:00
UserId : "new-pvt-domain-user" ,
2022-03-01 15:22:18 +01:00
DomainCategory : PrivateCategory ,
} ,
2022-03-10 13:47:36 +01:00
inputUpdateAttrs : true ,
inputInitUserParams : privateInitAccount ,
testingFunc : require . Equal ,
expectedMSG : "account IDs should match" ,
expectedUserRole : UserRoleUser ,
2022-09-29 10:51:18 +02:00
expectedDomain : privateDomain ,
2022-03-10 13:47:36 +01:00
expectedDomainCategory : PrivateCategory ,
expectedPrimaryDomainStatus : true ,
2022-06-09 13:14:34 +02:00
expectedCreatedBy : defaultInitAccount . UserId ,
expectedUsers : [ ] string { defaultInitAccount . UserId , "new-pvt-domain-user" } ,
2022-03-01 15:22:18 +01:00
}
testCase5 := test {
name : "Existing User With Existing Reclassified Private Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : defaultInitAccount . Domain ,
UserId : defaultInitAccount . UserId ,
DomainCategory : PrivateCategory ,
} ,
2022-03-10 13:47:36 +01:00
inputInitUserParams : defaultInitAccount ,
testingFunc : require . Equal ,
expectedMSG : "account IDs should match" ,
expectedUserRole : UserRoleAdmin ,
2022-09-29 10:51:18 +02:00
expectedDomain : defaultInitAccount . Domain ,
2022-03-10 13:47:36 +01:00
expectedDomainCategory : PrivateCategory ,
expectedPrimaryDomainStatus : true ,
2022-06-09 13:14:34 +02:00
expectedCreatedBy : defaultInitAccount . UserId ,
expectedUsers : [ ] string { defaultInitAccount . UserId } ,
2022-03-01 15:22:18 +01:00
}
2022-03-09 13:31:42 +01:00
testCase6 := test {
name : "Existing Account Id With Existing Reclassified Private Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : defaultInitAccount . Domain ,
UserId : defaultInitAccount . UserId ,
DomainCategory : PrivateCategory ,
} ,
2022-03-10 13:47:36 +01:00
inputUpdateClaimAccount : true ,
inputInitUserParams : defaultInitAccount ,
testingFunc : require . Equal ,
expectedMSG : "account IDs should match" ,
expectedUserRole : UserRoleAdmin ,
2022-09-29 10:51:18 +02:00
expectedDomain : defaultInitAccount . Domain ,
2022-03-10 13:47:36 +01:00
expectedDomainCategory : PrivateCategory ,
expectedPrimaryDomainStatus : true ,
2022-06-09 13:14:34 +02:00
expectedCreatedBy : defaultInitAccount . UserId ,
expectedUsers : [ ] string { defaultInitAccount . UserId } ,
2022-03-09 13:31:42 +01:00
}
2022-09-29 10:51:18 +02:00
testCase7 := test {
name : "User With Private Category And Empty Domain" ,
inputClaims : jwtclaims . AuthorizationClaims {
Domain : "" ,
UserId : "pvt-domain-user" ,
DomainCategory : PrivateCategory ,
} ,
inputInitUserParams : defaultInitAccount ,
testingFunc : require . NotEqual ,
expectedMSG : "account IDs shouldn't match" ,
expectedUserRole : UserRoleAdmin ,
expectedDomain : "" ,
expectedDomainCategory : "" ,
expectedPrimaryDomainStatus : false ,
expectedCreatedBy : "pvt-domain-user" ,
expectedUsers : [ ] string { "pvt-domain-user" } ,
}
for _ , testCase := range [ ] test { testCase1 , testCase2 , testCase3 , testCase4 , testCase5 , testCase6 , testCase7 } {
2022-03-01 15:22:18 +01:00
t . Run ( testCase . name , func ( t * testing . T ) {
manager , err := createManager ( t )
require . NoError ( t , err , "unable to create account manager" )
2022-11-07 17:52:23 +01:00
initAccount , err := manager . GetAccountByUserOrAccountID ( testCase . inputInitUserParams . UserId , testCase . inputInitUserParams . AccountId , testCase . inputInitUserParams . Domain )
2022-03-01 15:22:18 +01:00
require . NoError ( t , err , "create init user failed" )
if testCase . inputUpdateAttrs {
err = manager . updateAccountDomainAttributes ( initAccount , jwtclaims . AuthorizationClaims { UserId : testCase . inputInitUserParams . UserId , Domain : testCase . inputInitUserParams . Domain , DomainCategory : testCase . inputInitUserParams . DomainCategory } , true )
require . NoError ( t , err , "update init user failed" )
}
2022-03-09 13:31:42 +01:00
if testCase . inputUpdateClaimAccount {
testCase . inputClaims . AccountId = initAccount . Id
}
2022-11-11 20:36:45 +01:00
account , _ , err := manager . GetAccountFromToken ( testCase . inputClaims )
2022-03-01 15:22:18 +01:00
require . NoError ( t , err , "support function failed" )
2022-06-09 13:14:34 +02:00
verifyNewAccountHasDefaultFields ( t , account , testCase . expectedCreatedBy , testCase . inputClaims . Domain , testCase . expectedUsers )
verifyCanAddPeerToAccount ( t , manager , account , testCase . expectedCreatedBy )
2022-03-01 15:22:18 +01:00
testCase . testingFunc ( t , initAccount . Id , account . Id , testCase . expectedMSG )
2022-03-10 13:47:36 +01:00
require . EqualValues ( t , testCase . expectedUserRole , account . Users [ testCase . inputClaims . UserId ] . Role , "expected user role should match" )
require . EqualValues ( t , testCase . expectedDomainCategory , account . DomainCategory , "expected account domain category should match" )
require . EqualValues ( t , testCase . expectedPrimaryDomainStatus , account . IsDomainPrimaryAccount , "expected account primary status should match" )
2022-09-29 10:51:18 +02:00
require . EqualValues ( t , testCase . expectedDomain , account . Domain , "expected account domain should match" )
2022-03-01 15:22:18 +01:00
} )
}
}
2022-05-05 08:58:34 +02:00
2022-03-01 15:22:18 +01:00
func TestAccountManager_PrivateAccount ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
userId := "test_user"
account , err := manager . GetOrCreateAccountByUser ( userId , "" )
if err != nil {
t . Fatal ( err )
}
if account == nil {
t . Fatalf ( "expected to create an account for a user %s" , userId )
}
2022-11-07 17:52:23 +01:00
account , err = manager . Store . GetAccountByUser ( userId )
2022-03-01 15:22:18 +01:00
if err != nil {
t . Errorf ( "expected to get existing account after creation, no account was found for a user %s" , userId )
}
if account != nil && account . Users [ userId ] == nil {
2021-12-27 13:17:15 +01:00
t . Fatalf ( "expected to create an account for a user %s but no user was found after creation udner the account %s" , userId , account . Id )
2021-08-20 15:18:29 +02:00
}
2021-08-20 15:44:18 +02:00
}
2022-02-11 17:18:18 +01:00
func TestAccountManager_SetOrUpdateDomain ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
userId := "test_user"
domain := "hotmail.com"
account , err := manager . GetOrCreateAccountByUser ( userId , domain )
if err != nil {
t . Fatal ( err )
}
if account == nil {
t . Fatalf ( "expected to create an account for a user %s" , userId )
}
if account . Domain != domain {
t . Errorf ( "setting account domain failed, expected %s, got %s" , domain , account . Domain )
}
domain = "gmail.com"
account , err = manager . GetOrCreateAccountByUser ( userId , domain )
if err != nil {
t . Fatalf ( "got the following error while retrieving existing acc: %v" , err )
}
if account == nil {
t . Fatalf ( "expected to get an account for a user %s" , userId )
}
if account . Domain != domain {
t . Errorf ( "updating domain. expected %s got %s" , domain , account . Domain )
}
}
2022-01-24 11:21:30 +01:00
func TestAccountManager_GetAccountByUserOrAccountId ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
userId := "test_user"
2022-11-07 17:52:23 +01:00
account , err := manager . GetAccountByUserOrAccountID ( userId , "" , "" )
2022-01-24 11:21:30 +01:00
if err != nil {
t . Fatal ( err )
}
if account == nil {
t . Fatalf ( "expected to create an account for a user %s" , userId )
}
accountId := account . Id
2022-11-07 17:52:23 +01:00
_ , err = manager . GetAccountByUserOrAccountID ( "" , accountId , "" )
2022-01-24 11:21:30 +01:00
if err != nil {
t . Errorf ( "expected to get existing account after creation using userid, no account was found for a account %s" , accountId )
}
2022-11-07 17:52:23 +01:00
_ , err = manager . GetAccountByUserOrAccountID ( "" , "" , "" )
2022-01-24 11:21:30 +01:00
if err == nil {
t . Errorf ( "expected an error when user and account IDs are empty" )
}
}
2022-06-09 13:14:34 +02:00
func createAccount ( am * DefaultAccountManager , accountID , userID , domain string ) ( * Account , error ) {
account := newAccountWithId ( accountID , userID , domain )
err := am . Store . SaveAccount ( account )
if err != nil {
return nil , err
}
return account , nil
}
2021-08-20 15:44:18 +02:00
func TestAccountManager_AccountExists ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
expectedId := "test_account"
2021-12-27 13:17:15 +01:00
userId := "account_creator"
2022-06-09 13:14:34 +02:00
_ , err = createAccount ( manager , expectedId , userId , "" )
2021-08-20 15:44:18 +02:00
if err != nil {
t . Fatal ( err )
}
exists , err := manager . AccountExists ( expectedId )
if err != nil {
t . Fatal ( err )
}
if ! * exists {
t . Errorf ( "expected account to exist after creation, got false" )
}
}
func TestAccountManager_GetAccount ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
expectedId := "test_account"
2021-12-27 13:17:15 +01:00
userId := "account_creator"
2022-06-09 13:14:34 +02:00
account , err := createAccount ( manager , expectedId , userId , "" )
2021-08-20 15:44:18 +02:00
if err != nil {
t . Fatal ( err )
}
2022-05-21 15:21:39 +02:00
// AddAccount has been already tested so we can assume it is correct and compare results
2022-11-07 17:52:23 +01:00
getAccount , err := manager . Store . GetAccount ( account . Id )
2021-08-20 15:44:18 +02:00
if err != nil {
t . Fatal ( err )
return
}
if account . Id != getAccount . Id {
2021-08-20 22:33:43 +02:00
t . Errorf ( "expected account.Id %s, got %s" , account . Id , getAccount . Id )
2021-08-20 15:44:18 +02:00
}
for _ , peer := range account . Peers {
2023-02-03 10:33:28 +01:00
if _ , ok := getAccount . Peers [ peer . ID ] ; ! ok {
t . Errorf ( "expected account to have peer %s, not found" , peer . ID )
2021-08-20 15:44:18 +02:00
}
}
for _ , key := range account . SetupKeys {
if _ , ok := getAccount . SetupKeys [ key . Key ] ; ! ok {
t . Errorf ( "expected account to have setup key %s, not found" , key . Key )
}
}
2021-08-20 15:18:29 +02:00
}
func TestAccountManager_AddPeer ( t * testing . T ) {
2021-08-20 15:44:18 +02:00
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
2021-08-20 15:18:29 +02:00
2023-01-02 15:11:32 +01:00
account , err := createAccount ( manager , "test_account" , "account_creator" , "netbird.cloud" )
2021-08-20 15:18:29 +02:00
if err != nil {
t . Fatal ( err )
}
2022-05-21 15:21:39 +02:00
serial := account . Network . CurrentSerial ( ) // should be 0
2022-01-14 14:34:27 +01:00
2021-08-20 15:44:18 +02:00
var setupKey * SetupKey
for _ , key := range account . SetupKeys {
setupKey = key
}
if setupKey == nil {
t . Errorf ( "expecting account to have a default setup key" )
return
}
2021-08-20 15:18:29 +02:00
2022-03-10 18:18:38 +01:00
if account . Network . Serial != 0 {
t . Errorf ( "expecting account network to have an initial Serial=0" )
2022-01-14 14:34:27 +01:00
return
}
2022-01-16 17:10:36 +01:00
key , err := wgtypes . GeneratePrivateKey ( )
2021-08-20 15:18:29 +02:00
if err != nil {
t . Fatal ( err )
2021-08-20 15:44:18 +02:00
return
}
expectedPeerKey := key . PublicKey ( ) . String ( )
2022-05-05 20:02:15 +02:00
expectedSetupKey := setupKey . Key
2021-08-20 15:44:18 +02:00
2022-05-05 20:02:15 +02:00
peer , err := manager . AddPeer ( setupKey . Key , "" , & Peer {
2021-08-24 11:50:19 +02:00
Key : expectedPeerKey ,
Meta : PeerSystemMeta { } ,
Name : expectedPeerKey ,
} )
2021-08-20 15:44:18 +02:00
if err != nil {
t . Errorf ( "expecting peer to be added, got failure %v" , err )
return
}
2022-11-07 17:52:23 +01:00
account , err = manager . Store . GetAccount ( account . Id )
2022-01-14 14:34:27 +01:00
if err != nil {
t . Fatal ( err )
return
}
2021-08-20 15:44:18 +02:00
if peer . Key != expectedPeerKey {
t . Errorf ( "expecting just added peer to have key = %s, got %s" , expectedPeerKey , peer . Key )
}
2022-05-29 22:43:39 +02:00
if ! account . Network . Net . Contains ( peer . IP ) {
t . Errorf ( "expecting just added peer's IP %s to be in a network range %s" , peer . IP . String ( ) , account . Network . Net . String ( ) )
2022-05-05 20:02:15 +02:00
}
if peer . SetupKey != expectedSetupKey {
t . Errorf ( "expecting just added peer to have SetupKey = %s, got %s" , expectedSetupKey , peer . SetupKey )
}
if account . Network . CurrentSerial ( ) != 1 {
t . Errorf ( "expecting Network Serial=%d to be incremented by 1 and be equal to %d when adding new peer to account" , serial , account . Network . CurrentSerial ( ) )
}
2023-01-24 10:17:24 +01:00
ev := getEvent ( t , account . Id , manager , activity . PeerAddedWithSetupKey )
2023-01-02 15:11:32 +01:00
assert . NotNil ( t , ev )
assert . Equal ( t , account . Id , ev . AccountID )
assert . Equal ( t , peer . Name , ev . Meta [ "name" ] )
assert . Equal ( t , peer . FQDN ( account . Domain ) , ev . Meta [ "fqdn" ] )
assert . Equal ( t , setupKey . Id , ev . InitiatorID )
2023-02-03 10:33:28 +01:00
assert . Equal ( t , peer . ID , ev . TargetID )
2023-01-02 15:11:32 +01:00
assert . Equal ( t , peer . IP . String ( ) , fmt . Sprint ( ev . Meta [ "ip" ] ) )
2022-05-05 20:02:15 +02:00
}
func TestAccountManager_AddPeerWithUserID ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
2023-01-02 15:11:32 +01:00
account , err := manager . GetOrCreateAccountByUser ( userID , "netbird.cloud" )
2022-05-05 20:02:15 +02:00
if err != nil {
t . Fatal ( err )
}
2022-05-21 15:21:39 +02:00
serial := account . Network . CurrentSerial ( ) // should be 0
2022-05-05 20:02:15 +02:00
if account . Network . Serial != 0 {
t . Errorf ( "expecting account network to have an initial Serial=0" )
return
}
key , err := wgtypes . GeneratePrivateKey ( )
if err != nil {
t . Fatal ( err )
return
}
expectedPeerKey := key . PublicKey ( ) . String ( )
2023-01-02 15:11:32 +01:00
expectedUserID := userID
2022-05-05 20:02:15 +02:00
2023-01-02 15:11:32 +01:00
peer , err := manager . AddPeer ( "" , userID , & Peer {
2022-05-05 20:02:15 +02:00
Key : expectedPeerKey ,
Meta : PeerSystemMeta { } ,
Name : expectedPeerKey ,
} )
if err != nil {
t . Errorf ( "expecting peer to be added, got failure %v, account users: %v" , err , account . CreatedBy )
return
}
2022-11-07 17:52:23 +01:00
account , err = manager . Store . GetAccount ( account . Id )
2022-05-05 20:02:15 +02:00
if err != nil {
t . Fatal ( err )
return
}
2021-08-20 15:44:18 +02:00
if peer . Key != expectedPeerKey {
2022-05-05 20:02:15 +02:00
t . Errorf ( "expecting just added peer to have key = %s, got %s" , expectedPeerKey , peer . Key )
}
2022-05-29 22:43:39 +02:00
if ! account . Network . Net . Contains ( peer . IP ) {
t . Errorf ( "expecting just added peer's IP %s to be in a network range %s" , peer . IP . String ( ) , account . Network . Net . String ( ) )
2021-08-20 15:18:29 +02:00
}
2023-01-02 15:11:32 +01:00
if peer . UserID != expectedUserID {
t . Errorf ( "expecting just added peer to have UserID = %s, got %s" , expectedUserID , peer . UserID )
2022-05-05 20:02:15 +02:00
}
2022-03-10 18:18:38 +01:00
if account . Network . CurrentSerial ( ) != 1 {
t . Errorf ( "expecting Network Serial=%d to be incremented by 1 and be equal to %d when adding new peer to account" , serial , account . Network . CurrentSerial ( ) )
2022-01-14 14:34:27 +01:00
}
2023-01-02 15:11:32 +01:00
2023-01-24 10:17:24 +01:00
ev := getEvent ( t , account . Id , manager , activity . PeerAddedByUser )
2023-01-02 15:11:32 +01:00
assert . NotNil ( t , ev )
assert . Equal ( t , account . Id , ev . AccountID )
assert . Equal ( t , peer . Name , ev . Meta [ "name" ] )
assert . Equal ( t , peer . FQDN ( account . Domain ) , ev . Meta [ "fqdn" ] )
assert . Equal ( t , userID , ev . InitiatorID )
2023-02-03 10:33:28 +01:00
assert . Equal ( t , peer . ID , ev . TargetID )
2023-01-02 15:11:32 +01:00
assert . Equal ( t , peer . IP . String ( ) , fmt . Sprint ( ev . Meta [ "ip" ] ) )
2021-08-20 15:44:18 +02:00
}
2022-01-14 14:34:27 +01:00
2022-06-04 22:02:22 +02:00
func TestAccountManager_NetworkUpdates ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
2023-01-02 15:11:32 +01:00
userID := "account_creator"
account , err := createAccount ( manager , "test_account" , userID , "" )
2022-06-04 22:02:22 +02:00
if err != nil {
t . Fatal ( err )
}
var setupKey * SetupKey
for _ , key := range account . SetupKeys {
setupKey = key
if setupKey . Type == SetupKeyReusable {
break
}
}
if setupKey == nil {
t . Errorf ( "expecting account to have a default setup key" )
return
}
if account . Network . Serial != 0 {
t . Errorf ( "expecting account network to have an initial Serial=0" )
return
}
getPeer := func ( ) * Peer {
key , err := wgtypes . GeneratePrivateKey ( )
if err != nil {
t . Fatal ( err )
return nil
}
expectedPeerKey := key . PublicKey ( ) . String ( )
peer , err := manager . AddPeer ( setupKey . Key , "" , & Peer {
Key : expectedPeerKey ,
Meta : PeerSystemMeta { } ,
Name : expectedPeerKey ,
} )
if err != nil {
t . Fatalf ( "expecting peer1 to be added, got failure %v" , err )
return nil
}
return peer
}
peer1 := getPeer ( )
peer2 := getPeer ( )
peer3 := getPeer ( )
2022-11-07 17:52:23 +01:00
account , err = manager . Store . GetAccount ( account . Id )
2022-06-04 22:02:22 +02:00
if err != nil {
t . Fatal ( err )
return
}
2023-02-03 10:33:28 +01:00
updMsg := manager . peersUpdateManager . CreateChannel ( peer1 . ID )
defer manager . peersUpdateManager . CloseChannel ( peer1 . ID )
2022-06-04 22:02:22 +02:00
group := Group {
ID : "group-id" ,
Name : "GroupA" ,
2023-02-03 10:33:28 +01:00
Peers : [ ] string { peer1 . ID , peer2 . ID , peer3 . ID } ,
2022-06-04 22:02:22 +02:00
}
rule := Rule {
Source : [ ] string { "group-id" } ,
Destination : [ ] string { "group-id" } ,
Flow : TrafficFlowBidirect ,
}
wg := sync . WaitGroup { }
t . Run ( "save group update" , func ( t * testing . T ) {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
message := <- updMsg
networkMap := message . Update . GetNetworkMap ( )
if len ( networkMap . RemotePeers ) != 2 {
t . Errorf ( "mismatch peers count: 2 expected, got %v" , len ( networkMap . RemotePeers ) )
}
} ( )
2023-01-02 15:11:32 +01:00
if err := manager . SaveGroup ( account . Id , userID , & group ) ; err != nil {
2022-06-04 22:02:22 +02:00
t . Errorf ( "save group: %v" , err )
return
}
wg . Wait ( )
} )
t . Run ( "delete rule update" , func ( t * testing . T ) {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
message := <- updMsg
networkMap := message . Update . GetNetworkMap ( )
if len ( networkMap . RemotePeers ) != 0 {
t . Errorf ( "mismatch peers count: 0 expected, got %v" , len ( networkMap . RemotePeers ) )
}
} ( )
var defaultRule * Rule
for _ , r := range account . Rules {
defaultRule = r
}
2023-01-02 15:11:32 +01:00
if err := manager . DeleteRule ( account . Id , defaultRule . ID , userID ) ; err != nil {
2022-06-04 22:02:22 +02:00
t . Errorf ( "delete default rule: %v" , err )
return
}
wg . Wait ( )
} )
t . Run ( "save rule update" , func ( t * testing . T ) {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
message := <- updMsg
networkMap := message . Update . GetNetworkMap ( )
if len ( networkMap . RemotePeers ) != 2 {
t . Errorf ( "mismatch peers count: 2 expected, got %v" , len ( networkMap . RemotePeers ) )
}
} ( )
2023-01-02 15:11:32 +01:00
if err := manager . SaveRule ( account . Id , userID , & rule ) ; err != nil {
2022-06-04 22:02:22 +02:00
t . Errorf ( "delete default rule: %v" , err )
return
}
wg . Wait ( )
} )
t . Run ( "delete peer update" , func ( t * testing . T ) {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
message := <- updMsg
networkMap := message . Update . GetNetworkMap ( )
if len ( networkMap . RemotePeers ) != 1 {
t . Errorf ( "mismatch peers count: 1 expected, got %v" , len ( networkMap . RemotePeers ) )
}
} ( )
2023-02-03 10:33:28 +01:00
if _ , err := manager . DeletePeer ( account . Id , peer3 . ID , userID ) ; err != nil {
2022-06-04 22:02:22 +02:00
t . Errorf ( "delete peer: %v" , err )
return
}
wg . Wait ( )
} )
t . Run ( "delete group update" , func ( t * testing . T ) {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
message := <- updMsg
networkMap := message . Update . GetNetworkMap ( )
if len ( networkMap . RemotePeers ) != 0 {
t . Errorf ( "mismatch peers count: 0 expected, got %v" , len ( networkMap . RemotePeers ) )
}
} ( )
if err := manager . DeleteGroup ( account . Id , group . ID ) ; err != nil {
t . Errorf ( "delete group rule: %v" , err )
return
}
wg . Wait ( )
} )
}
2022-01-14 14:34:27 +01:00
func TestAccountManager_DeletePeer ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
2023-01-02 15:11:32 +01:00
userID := "account_creator"
account , err := createAccount ( manager , "test_account" , userID , "netbird.cloud" )
2022-01-14 14:34:27 +01:00
if err != nil {
t . Fatal ( err )
}
var setupKey * SetupKey
for _ , key := range account . SetupKeys {
setupKey = key
}
key , err := wgtypes . GenerateKey ( )
if err != nil {
t . Fatal ( err )
return
}
peerKey := key . PublicKey ( ) . String ( )
2023-01-02 15:11:32 +01:00
peer , err := manager . AddPeer ( setupKey . Key , "" , & Peer {
2022-01-14 14:34:27 +01:00
Key : peerKey ,
Meta : PeerSystemMeta { } ,
Name : peerKey ,
} )
if err != nil {
t . Errorf ( "expecting peer to be added, got failure %v" , err )
return
}
2023-01-02 15:11:32 +01:00
_ , err = manager . DeletePeer ( account . Id , peerKey , userID )
2022-01-14 14:34:27 +01:00
if err != nil {
return
}
2022-11-07 17:52:23 +01:00
account , err = manager . Store . GetAccount ( account . Id )
2022-01-14 14:34:27 +01:00
if err != nil {
t . Fatal ( err )
return
}
2022-03-10 18:18:38 +01:00
if account . Network . CurrentSerial ( ) != 2 {
t . Errorf ( "expecting Network Serial=%d to be incremented and be equal to 2 after adding and deleteing a peer" , account . Network . CurrentSerial ( ) )
2022-01-14 14:34:27 +01:00
}
2023-01-02 15:11:32 +01:00
2023-01-24 10:17:24 +01:00
ev := getEvent ( t , account . Id , manager , activity . PeerRemovedByUser )
2023-01-02 15:11:32 +01:00
assert . NotNil ( t , ev )
assert . Equal ( t , account . Id , ev . AccountID )
assert . Equal ( t , peer . Name , ev . Meta [ "name" ] )
assert . Equal ( t , peer . FQDN ( account . Domain ) , ev . Meta [ "fqdn" ] )
assert . Equal ( t , userID , ev . InitiatorID )
assert . Equal ( t , peer . IP . String ( ) , ev . TargetID )
assert . Equal ( t , peer . IP . String ( ) , fmt . Sprint ( ev . Meta [ "ip" ] ) )
2022-01-14 14:34:27 +01:00
}
2023-01-24 10:17:24 +01:00
func getEvent ( t * testing . T , accountID string , manager AccountManager , eventType activity . Activity ) * activity . Event {
for {
select {
case <- time . After ( time . Second ) :
t . Fatal ( "no PeerAddedWithSetupKey event was generated" )
default :
events , err := manager . GetEvents ( accountID , userID )
if err != nil {
t . Fatal ( err )
}
for _ , event := range events {
if event . Activity == eventType {
return event
}
}
}
}
}
2022-01-14 14:34:27 +01:00
2022-05-05 08:58:34 +02:00
func TestGetUsersFromAccount ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
}
users := map [ string ] * User { "1" : { Id : "1" , Role : "admin" } , "2" : { Id : "2" , Role : "user" } , "3" : { Id : "3" , Role : "user" } }
accountId := "test_account_id"
2022-06-09 13:14:34 +02:00
account , err := createAccount ( manager , accountId , users [ "1" ] . Id , "" )
2022-05-05 08:58:34 +02:00
if err != nil {
t . Fatal ( err )
}
// add a user to the account
for _ , user := range users {
account . Users [ user . Id ] = user
}
2022-11-05 10:24:50 +01:00
userInfos , err := manager . GetUsersFromAccount ( accountId , "1" )
2022-05-05 08:58:34 +02:00
if err != nil {
t . Fatal ( err )
}
for _ , userInfo := range userInfos {
id := userInfo . ID
assert . Equal ( t , userInfo . ID , users [ id ] . Id )
2022-05-29 22:43:39 +02:00
assert . Equal ( t , userInfo . Role , string ( users [ id ] . Role ) )
2022-05-05 08:58:34 +02:00
assert . Equal ( t , userInfo . Name , "" )
assert . Equal ( t , userInfo . Email , "" )
}
}
2022-05-23 13:03:57 +02:00
func TestAccountManager_UpdatePeerMeta ( t * testing . T ) {
manager , err := createManager ( t )
if err != nil {
t . Fatal ( err )
return
}
2022-06-09 13:14:34 +02:00
account , err := createAccount ( manager , "test_account" , "account_creator" , "" )
2022-05-23 13:03:57 +02:00
if err != nil {
t . Fatal ( err )
}
var setupKey * SetupKey
for _ , key := range account . SetupKeys {
setupKey = key
}
key , err := wgtypes . GeneratePrivateKey ( )
if err != nil {
t . Fatal ( err )
return
}
peer , err := manager . AddPeer ( setupKey . Key , "" , & Peer {
Key : key . PublicKey ( ) . String ( ) ,
Meta : PeerSystemMeta {
Hostname : "Hostname" ,
GoOS : "GoOS" ,
Kernel : "Kernel" ,
Core : "Core" ,
Platform : "Platform" ,
OS : "OS" ,
WtVersion : "WtVersion" ,
} ,
Name : key . PublicKey ( ) . String ( ) ,
} )
if err != nil {
t . Errorf ( "expecting peer to be added, got failure %v" , err )
return
}
newMeta := PeerSystemMeta {
Hostname : "new-Hostname" ,
GoOS : "new-GoOS" ,
Kernel : "new-Kernel" ,
Core : "new-Core" ,
Platform : "new-Platform" ,
OS : "new-OS" ,
WtVersion : "new-WtVersion" ,
}
2023-02-03 10:33:28 +01:00
err = manager . UpdatePeerMeta ( peer . ID , newMeta )
2022-05-23 13:03:57 +02:00
if err != nil {
t . Error ( err )
return
}
2023-02-03 10:33:28 +01:00
p , err := manager . GetPeerByKey ( peer . Key )
2022-05-23 13:03:57 +02:00
if err != nil {
return
}
if err != nil {
t . Fatal ( err )
return
}
assert . Equal ( t , newMeta , p . Meta )
}
2022-11-07 12:10:56 +01:00
func TestAccount_GetPeerRules ( t * testing . T ) {
groups := map [ string ] * Group {
"group_1" : {
ID : "group_1" ,
Name : "group_1" ,
Peers : [ ] string { "peer-1" , "peer-2" } ,
} ,
"group_2" : {
ID : "group_2" ,
Name : "group_2" ,
Peers : [ ] string { "peer-2" , "peer-3" } ,
} ,
"group_3" : {
ID : "group_3" ,
Name : "group_3" ,
Peers : [ ] string { "peer-4" } ,
} ,
"group_4" : {
ID : "group_4" ,
Name : "group_4" ,
Peers : [ ] string { "peer-1" } ,
} ,
"group_5" : {
ID : "group_5" ,
Name : "group_5" ,
Peers : [ ] string { "peer-1" } ,
} ,
}
rules := map [ string ] * Rule {
"rule-1" : {
ID : "rule-1" ,
Name : "rule-1" ,
Description : "rule-1" ,
Disabled : false ,
Source : [ ] string { "group_1" , "group_5" } ,
Destination : [ ] string { "group_2" } ,
Flow : 0 ,
} ,
"rule-2" : {
ID : "rule-2" ,
Name : "rule-2" ,
Description : "rule-2" ,
Disabled : false ,
Source : [ ] string { "group_1" } ,
Destination : [ ] string { "group_1" } ,
Flow : 0 ,
} ,
"rule-3" : {
ID : "rule-3" ,
Name : "rule-3" ,
Description : "rule-3" ,
Disabled : false ,
Source : [ ] string { "group_3" } ,
Destination : [ ] string { "group_3" } ,
Flow : 0 ,
} ,
}
account := & Account {
Groups : groups ,
Rules : rules ,
}
srcRules , dstRules := account . GetPeerRules ( "peer-1" )
assert . Equal ( t , 2 , len ( srcRules ) )
assert . Equal ( t , 1 , len ( dstRules ) )
}
func TestFileStore_GetRoutesByPrefix ( t * testing . T ) {
_ , prefix , err := route . ParseNetwork ( "192.168.64.0/24" )
if err != nil {
t . Fatal ( err )
}
account := & Account {
Routes : map [ string ] * route . Route {
"route-1" : {
ID : "route-1" ,
Network : prefix ,
NetID : "network-1" ,
Description : "network-1" ,
Peer : "peer-1" ,
NetworkType : 0 ,
Masquerade : false ,
Metric : 999 ,
Enabled : true ,
} ,
"route-2" : {
ID : "route-2" ,
Network : prefix ,
NetID : "network-1" ,
Description : "network-1" ,
Peer : "peer-2" ,
NetworkType : 0 ,
Masquerade : false ,
Metric : 999 ,
Enabled : true ,
} ,
} ,
}
routes := account . GetRoutesByPrefix ( prefix )
assert . Len ( t , routes , 2 )
routeIDs := make ( map [ string ] struct { } , 2 )
for _ , r := range routes {
routeIDs [ r . ID ] = struct { } { }
}
assert . Contains ( t , routeIDs , "route-1" )
assert . Contains ( t , routeIDs , "route-2" )
}
2022-12-06 10:11:57 +01:00
func TestAccount_GetRoutesToSync ( t * testing . T ) {
2022-11-07 12:10:56 +01:00
_ , prefix , err := route . ParseNetwork ( "192.168.64.0/24" )
if err != nil {
t . Fatal ( err )
}
2022-12-08 15:15:50 +01:00
_ , prefix2 , err := route . ParseNetwork ( "192.168.0.0/24" )
if err != nil {
t . Fatal ( err )
}
2022-11-07 12:10:56 +01:00
account := & Account {
Peers : map [ string ] * Peer {
"peer-1" : { Key : "peer-1" } , "peer-2" : { Key : "peer-2" } , "peer-3" : { Key : "peer-1" } ,
} ,
2022-12-06 10:11:57 +01:00
Groups : map [ string ] * Group { "group1" : { ID : "group1" , Peers : [ ] string { "peer-1" , "peer-2" } } } ,
2022-11-07 12:10:56 +01:00
Routes : map [ string ] * route . Route {
"route-1" : {
ID : "route-1" ,
Network : prefix ,
NetID : "network-1" ,
Description : "network-1" ,
Peer : "peer-1" ,
NetworkType : 0 ,
Masquerade : false ,
Metric : 999 ,
Enabled : true ,
2022-12-06 10:11:57 +01:00
Groups : [ ] string { "group1" } ,
2022-11-07 12:10:56 +01:00
} ,
"route-2" : {
ID : "route-2" ,
2022-12-08 15:15:50 +01:00
Network : prefix2 ,
NetID : "network-2" ,
Description : "network-2" ,
Peer : "peer-2" ,
NetworkType : 0 ,
Masquerade : false ,
Metric : 999 ,
Enabled : true ,
Groups : [ ] string { "group1" } ,
} ,
"route-3" : {
ID : "route-3" ,
2022-11-07 12:10:56 +01:00
Network : prefix ,
NetID : "network-1" ,
Description : "network-1" ,
Peer : "peer-2" ,
NetworkType : 0 ,
Masquerade : false ,
Metric : 999 ,
Enabled : true ,
2022-12-06 10:11:57 +01:00
Groups : [ ] string { "group1" } ,
2022-11-07 12:10:56 +01:00
} ,
} ,
}
2022-12-06 10:11:57 +01:00
routes := account . getRoutesToSync ( "peer-2" , [ ] * Peer { { Key : "peer-1" } , { Key : "peer-3" } } )
2022-11-07 12:10:56 +01:00
assert . Len ( t , routes , 2 )
routeIDs := make ( map [ string ] struct { } , 2 )
for _ , r := range routes {
routeIDs [ r . ID ] = struct { } { }
}
assert . Contains ( t , routeIDs , "route-2" )
2022-12-08 15:15:50 +01:00
assert . Contains ( t , routeIDs , "route-3" )
2022-11-07 12:10:56 +01:00
2022-12-06 10:11:57 +01:00
emptyRoutes := account . getRoutesToSync ( "peer-3" , [ ] * Peer { { Key : "peer-1" } , { Key : "peer-2" } } )
assert . Len ( t , emptyRoutes , 0 )
2022-11-07 12:10:56 +01:00
}
2022-11-07 17:37:28 +01:00
func TestAccount_Copy ( t * testing . T ) {
account := & Account {
Id : "account1" ,
CreatedBy : "tester" ,
Domain : "test.com" ,
DomainCategory : "public" ,
IsDomainPrimaryAccount : true ,
SetupKeys : map [ string ] * SetupKey {
"setup1" : {
Id : "setup1" ,
AutoGroups : [ ] string { "group1" } ,
} ,
} ,
Network : & Network {
Id : "net1" ,
} ,
Peers : map [ string ] * Peer {
"peer1" : {
Key : "key1" ,
} ,
} ,
Users : map [ string ] * User {
"user1" : {
Id : "user1" ,
Role : UserRoleAdmin ,
AutoGroups : [ ] string { "group1" } ,
} ,
} ,
Groups : map [ string ] * Group {
"group1" : {
ID : "group1" ,
} ,
} ,
Rules : map [ string ] * Rule {
"rule1" : {
ID : "rule1" ,
} ,
} ,
Routes : map [ string ] * route . Route {
"route1" : {
ID : "route1" ,
} ,
} ,
NameServerGroups : map [ string ] * nbdns . NameServerGroup {
"nsGroup1" : {
ID : "nsGroup1" ,
} ,
} ,
2023-02-13 15:07:15 +01:00
DNSSettings : & DNSSettings { DisabledManagementGroups : [ ] string { } } ,
Settings : & Settings { } ,
2022-11-07 17:37:28 +01:00
}
err := hasNilField ( account )
if err != nil {
t . Fatal ( err )
}
accountCopy := account . Copy ( )
assert . Equal ( t , account , accountCopy , "account copy returned a different value than expected" )
}
// hasNilField validates pointers, maps and slices if they are nil
func hasNilField ( x interface { } ) error {
rv := reflect . ValueOf ( x )
rv = rv . Elem ( )
for i := 0 ; i < rv . NumField ( ) ; i ++ {
if f := rv . Field ( i ) ; f . IsValid ( ) {
k := f . Kind ( )
switch k {
case reflect . Ptr :
if f . IsNil ( ) {
return fmt . Errorf ( "field %s is nil" , f . String ( ) )
}
case reflect . Map , reflect . Slice :
if f . Len ( ) == 0 || f . IsNil ( ) {
return fmt . Errorf ( "field %s is nil" , f . String ( ) )
}
}
}
}
return nil
}
2023-02-16 12:00:41 +01:00
func TestDefaultAccountManager_DefaultAccountSettings ( t * testing . T ) {
manager , err := createManager ( t )
require . NoError ( t , err , "unable to create account manager" )
account , err := manager . GetAccountByUserOrAccountID ( userID , "" , "" )
require . NoError ( t , err , "unable to create an account" )
assert . NotNil ( t , account . Settings )
assert . Equal ( t , account . Settings . PeerLoginExpirationEnabled , true )
assert . Equal ( t , account . Settings . PeerLoginExpiration , 24 * time . Hour )
}
2023-02-27 16:44:26 +01:00
func TestDefaultAccountManager_UpdatePeer_PeerLoginExpiration ( t * testing . T ) {
manager , err := createManager ( t )
require . NoError ( t , err , "unable to create account manager" )
account , err := manager . GetAccountByUserOrAccountID ( userID , "" , "" )
require . NoError ( t , err , "unable to create an account" )
key , err := wgtypes . GenerateKey ( )
require . NoError ( t , err , "unable to generate WireGuard key" )
peer , err := manager . AddPeer ( "" , userID , & Peer {
Key : key . PublicKey ( ) . String ( ) ,
Meta : PeerSystemMeta { } ,
Name : "test-peer" ,
LoginExpirationEnabled : true ,
} )
require . NoError ( t , err , "unable to add peer" )
err = manager . MarkPeerConnected ( key . PublicKey ( ) . String ( ) , true )
require . NoError ( t , err , "unable to mark peer connected" )
account , err = manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Hour ,
PeerLoginExpirationEnabled : true } )
require . NoError ( t , err , "expecting to update account settings successfully but got error" )
wg := & sync . WaitGroup { }
wg . Add ( 2 )
manager . peerLoginExpiry = & MockScheduler {
CancelFunc : func ( IDs [ ] string ) {
wg . Done ( )
} ,
ScheduleFunc : func ( in time . Duration , ID string , job func ( ) ( nextRunIn time . Duration , reschedule bool ) ) {
wg . Done ( )
} ,
}
// disable expiration first
update := peer . Copy ( )
update . LoginExpirationEnabled = false
_ , err = manager . UpdatePeer ( account . Id , userID , update )
require . NoError ( t , err , "unable to update peer" )
// enabling expiration should trigger the routine
update . LoginExpirationEnabled = true
_ , err = manager . UpdatePeer ( account . Id , userID , update )
require . NoError ( t , err , "unable to update peer" )
failed := waitTimeout ( wg , time . Second )
if failed {
t . Fatal ( "timeout while waiting for test to finish" )
}
}
func TestDefaultAccountManager_MarkPeerConnected_PeerLoginExpiration ( t * testing . T ) {
manager , err := createManager ( t )
require . NoError ( t , err , "unable to create account manager" )
account , err := manager . GetAccountByUserOrAccountID ( userID , "" , "" )
require . NoError ( t , err , "unable to create an account" )
key , err := wgtypes . GenerateKey ( )
require . NoError ( t , err , "unable to generate WireGuard key" )
_ , err = manager . AddPeer ( "" , userID , & Peer {
Key : key . PublicKey ( ) . String ( ) ,
Meta : PeerSystemMeta { } ,
Name : "test-peer" ,
LoginExpirationEnabled : true ,
} )
require . NoError ( t , err , "unable to add peer" )
_ , err = manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Hour ,
PeerLoginExpirationEnabled : true } )
require . NoError ( t , err , "expecting to update account settings successfully but got error" )
wg := & sync . WaitGroup { }
wg . Add ( 2 )
manager . peerLoginExpiry = & MockScheduler {
CancelFunc : func ( IDs [ ] string ) {
wg . Done ( )
} ,
ScheduleFunc : func ( in time . Duration , ID string , job func ( ) ( nextRunIn time . Duration , reschedule bool ) ) {
wg . Done ( )
} ,
}
// when we mark peer as connected, the peer login expiration routine should trigger
err = manager . MarkPeerConnected ( key . PublicKey ( ) . String ( ) , true )
require . NoError ( t , err , "unable to mark peer connected" )
failed := waitTimeout ( wg , time . Second )
if failed {
t . Fatal ( "timeout while waiting for test to finish" )
}
}
func TestDefaultAccountManager_UpdateAccountSettings_PeerLoginExpiration ( t * testing . T ) {
manager , err := createManager ( t )
require . NoError ( t , err , "unable to create account manager" )
account , err := manager . GetAccountByUserOrAccountID ( userID , "" , "" )
require . NoError ( t , err , "unable to create an account" )
key , err := wgtypes . GenerateKey ( )
require . NoError ( t , err , "unable to generate WireGuard key" )
_ , err = manager . AddPeer ( "" , userID , & Peer {
Key : key . PublicKey ( ) . String ( ) ,
Meta : PeerSystemMeta { } ,
Name : "test-peer" ,
LoginExpirationEnabled : true ,
} )
require . NoError ( t , err , "unable to add peer" )
err = manager . MarkPeerConnected ( key . PublicKey ( ) . String ( ) , true )
require . NoError ( t , err , "unable to mark peer connected" )
wg := & sync . WaitGroup { }
wg . Add ( 2 )
manager . peerLoginExpiry = & MockScheduler {
CancelFunc : func ( IDs [ ] string ) {
wg . Done ( )
} ,
ScheduleFunc : func ( in time . Duration , ID string , job func ( ) ( nextRunIn time . Duration , reschedule bool ) ) {
wg . Done ( )
} ,
}
// enabling PeerLoginExpirationEnabled should trigger the expiration job
account , err = manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Hour ,
PeerLoginExpirationEnabled : true } )
require . NoError ( t , err , "expecting to update account settings successfully but got error" )
failed := waitTimeout ( wg , time . Second )
if failed {
t . Fatal ( "timeout while waiting for test to finish" )
}
wg . Add ( 1 )
// disabling PeerLoginExpirationEnabled should trigger cancel
_ , err = manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Hour ,
PeerLoginExpirationEnabled : false } )
require . NoError ( t , err , "expecting to update account settings successfully but got error" )
failed = waitTimeout ( wg , time . Second )
if failed {
t . Fatal ( "timeout while waiting for test to finish" )
}
}
2023-02-16 12:00:41 +01:00
func TestDefaultAccountManager_UpdateAccountSettings ( t * testing . T ) {
manager , err := createManager ( t )
require . NoError ( t , err , "unable to create account manager" )
account , err := manager . GetAccountByUserOrAccountID ( userID , "" , "" )
require . NoError ( t , err , "unable to create an account" )
updated , err := manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Hour ,
PeerLoginExpirationEnabled : false } )
require . NoError ( t , err , "expecting to update account settings successfully but got error" )
assert . False ( t , updated . Settings . PeerLoginExpirationEnabled )
assert . Equal ( t , updated . Settings . PeerLoginExpiration , time . Hour )
account , err = manager . GetAccountByUserOrAccountID ( "" , account . Id , "" )
require . NoError ( t , err , "unable to get account by ID" )
assert . False ( t , account . Settings . PeerLoginExpirationEnabled )
assert . Equal ( t , account . Settings . PeerLoginExpiration , time . Hour )
_ , err = manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Second ,
PeerLoginExpirationEnabled : false } )
require . Error ( t , err , "expecting to fail when providing PeerLoginExpiration less than one hour" )
_ , err = manager . UpdateAccountSettings ( account . Id , userID , & Settings {
PeerLoginExpiration : time . Hour * 24 * 181 ,
PeerLoginExpirationEnabled : false } )
require . Error ( t , err , "expecting to fail when providing PeerLoginExpiration more than 180 days" )
}
2022-11-07 17:37:28 +01:00
2023-02-27 16:44:26 +01:00
func TestAccount_GetExpiredPeers ( t * testing . T ) {
type test struct {
name string
peers map [ string ] * Peer
expectedPeers map [ string ] struct { }
}
testCases := [ ] test {
{
name : "Peers with login expiration disabled, no expired peers" ,
peers : map [ string ] * Peer {
"peer-1" : {
LoginExpirationEnabled : false ,
} ,
"peer-2" : {
LoginExpirationEnabled : false ,
} ,
} ,
expectedPeers : map [ string ] struct { } { } ,
} ,
{
name : "Two peers expired" ,
peers : map [ string ] * Peer {
"peer-1" : {
ID : "peer-1" ,
LoginExpirationEnabled : true ,
Status : & PeerStatus {
LastSeen : time . Now ( ) ,
Connected : true ,
LoginExpired : false ,
} ,
LastLogin : time . Now ( ) . Add ( - 30 * time . Minute ) ,
} ,
"peer-2" : {
ID : "peer-2" ,
LoginExpirationEnabled : true ,
Status : & PeerStatus {
LastSeen : time . Now ( ) ,
Connected : true ,
LoginExpired : false ,
} ,
LastLogin : time . Now ( ) . Add ( - 2 * time . Hour ) ,
} ,
"peer-3" : {
ID : "peer-3" ,
LoginExpirationEnabled : true ,
Status : & PeerStatus {
LastSeen : time . Now ( ) ,
Connected : true ,
LoginExpired : false ,
} ,
LastLogin : time . Now ( ) . Add ( - 1 * time . Hour ) ,
} ,
} ,
expectedPeers : map [ string ] struct { } {
"peer-2" : { } ,
"peer-3" : { } ,
} ,
} ,
}
for _ , testCase := range testCases {
t . Run ( testCase . name , func ( t * testing . T ) {
account := & Account {
Peers : testCase . peers ,
Settings : & Settings {
PeerLoginExpirationEnabled : true ,
PeerLoginExpiration : time . Hour ,
} ,
}
expiredPeers := account . GetExpiredPeers ( )
assert . Len ( t , expiredPeers , len ( testCase . expectedPeers ) )
for _ , peer := range expiredPeers {
if _ , ok := testCase . expectedPeers [ peer . ID ] ; ! ok {
t . Fatalf ( "expected to have peer %s expired" , peer . ID )
}
}
} )
}
}
func TestAccount_GetPeersWithExpiration ( t * testing . T ) {
type test struct {
name string
peers map [ string ] * Peer
expectedPeers map [ string ] struct { }
}
testCases := [ ] test {
{
name : "No account peers, no peers with expiration" ,
peers : map [ string ] * Peer { } ,
expectedPeers : map [ string ] struct { } { } ,
} ,
{
name : "Peers with login expiration disabled, no peers with expiration" ,
peers : map [ string ] * Peer {
"peer-1" : {
LoginExpirationEnabled : false ,
} ,
"peer-2" : {
LoginExpirationEnabled : false ,
} ,
} ,
expectedPeers : map [ string ] struct { } { } ,
} ,
{
name : "Peers with login expiration enabled, return peers with expiration" ,
peers : map [ string ] * Peer {
"peer-1" : {
ID : "peer-1" ,
LoginExpirationEnabled : true ,
} ,
"peer-2" : {
LoginExpirationEnabled : false ,
} ,
} ,
expectedPeers : map [ string ] struct { } {
"peer-1" : { } ,
} ,
} ,
}
for _ , testCase := range testCases {
t . Run ( testCase . name , func ( t * testing . T ) {
account := & Account {
Peers : testCase . peers ,
}
actual := account . GetPeersWithExpiration ( )
assert . Len ( t , actual , len ( testCase . expectedPeers ) )
if len ( testCase . expectedPeers ) > 0 {
for k := range testCase . expectedPeers {
contains := false
for _ , peer := range actual {
if k == peer . ID {
contains = true
}
}
assert . True ( t , contains )
}
}
} )
}
}
func TestAccount_GetNextPeerExpiration ( t * testing . T ) {
type test struct {
name string
peers map [ string ] * Peer
expiration time . Duration
expirationEnabled bool
expectedNextRun bool
expectedNextExpiration time . Duration
}
expectedNextExpiration := time . Minute
testCases := [ ] test {
{
name : "No peers, no expiration" ,
peers : map [ string ] * Peer { } ,
expiration : time . Second ,
expirationEnabled : false ,
expectedNextRun : false ,
expectedNextExpiration : time . Duration ( 0 ) ,
} ,
{
name : "No connected peers, no expiration" ,
peers : map [ string ] * Peer {
"peer-1" : {
Status : & PeerStatus {
Connected : false ,
} ,
LoginExpirationEnabled : true ,
} ,
"peer-2" : {
Status : & PeerStatus {
Connected : true ,
} ,
LoginExpirationEnabled : false ,
} ,
} ,
expiration : time . Second ,
expirationEnabled : false ,
expectedNextRun : false ,
expectedNextExpiration : time . Duration ( 0 ) ,
} ,
{
name : "Connected peers with disabled expiration, no expiration" ,
peers : map [ string ] * Peer {
"peer-1" : {
Status : & PeerStatus {
Connected : true ,
} ,
LoginExpirationEnabled : false ,
} ,
"peer-2" : {
Status : & PeerStatus {
Connected : true ,
} ,
LoginExpirationEnabled : false ,
} ,
} ,
expiration : time . Second ,
expirationEnabled : false ,
expectedNextRun : false ,
expectedNextExpiration : time . Duration ( 0 ) ,
} ,
{
name : "Expired peers, no expiration" ,
peers : map [ string ] * Peer {
"peer-1" : {
Status : & PeerStatus {
Connected : true ,
LoginExpired : true ,
} ,
LoginExpirationEnabled : true ,
} ,
"peer-2" : {
Status : & PeerStatus {
Connected : true ,
LoginExpired : true ,
} ,
LoginExpirationEnabled : true ,
} ,
} ,
expiration : time . Second ,
expirationEnabled : false ,
expectedNextRun : false ,
expectedNextExpiration : time . Duration ( 0 ) ,
} ,
{
name : "To be expired peer, return expiration" ,
peers : map [ string ] * Peer {
"peer-1" : {
Status : & PeerStatus {
Connected : true ,
LoginExpired : false ,
} ,
LoginExpirationEnabled : true ,
LastLogin : time . Now ( ) ,
} ,
"peer-2" : {
Status : & PeerStatus {
Connected : true ,
LoginExpired : true ,
} ,
LoginExpirationEnabled : true ,
} ,
} ,
expiration : time . Minute ,
expirationEnabled : false ,
expectedNextRun : true ,
expectedNextExpiration : expectedNextExpiration ,
} ,
}
for _ , testCase := range testCases {
t . Run ( testCase . name , func ( t * testing . T ) {
account := & Account {
Peers : testCase . peers ,
Settings : & Settings { PeerLoginExpiration : testCase . expiration , PeerLoginExpirationEnabled : testCase . expirationEnabled } ,
}
expiration , ok := account . GetNextPeerExpiration ( )
assert . Equal ( t , ok , testCase . expectedNextRun )
if testCase . expectedNextRun {
assert . True ( t , expiration >= 0 && expiration <= testCase . expectedNextExpiration )
} else {
assert . Equal ( t , expiration , testCase . expectedNextExpiration )
}
} )
}
}
2022-02-22 11:28:19 +01:00
func createManager ( t * testing . T ) ( * DefaultAccountManager , error ) {
2021-08-20 15:44:18 +02:00
store , err := createStore ( t )
if err != nil {
return nil , err
}
2023-01-02 15:11:32 +01:00
eventStore := & activity . InMemoryEventStore { }
return BuildManager ( store , NewPeersUpdateManager ( ) , nil , "" , "netbird.cloud" , eventStore )
2021-08-20 15:18:29 +02:00
}
func createStore ( t * testing . T ) ( Store , error ) {
dataDir := t . TempDir ( )
2022-11-08 10:46:12 +01:00
store , err := NewFileStore ( dataDir )
2021-08-20 15:18:29 +02:00
if err != nil {
return nil , err
}
return store , nil
}
2023-02-27 16:44:26 +01:00
func waitTimeout ( wg * sync . WaitGroup , timeout time . Duration ) bool {
c := make ( chan struct { } )
go func ( ) {
defer close ( c )
wg . Wait ( )
} ( )
select {
case <- c :
return false
case <- time . After ( timeout ) :
return true
}
}