package routers import ( "context" "errors" "fmt" "github.com/rs/xid" s "github.com/netbirdio/netbird/management/server" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/networks/routers/types" networkTypes "github.com/netbirdio/netbird/management/server/networks/types" "github.com/netbirdio/netbird/management/server/permissions" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/store" ) type Manager interface { GetAllRoutersInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkRouter, error) GetAllRoutersInAccount(ctx context.Context, accountID, userID string) (map[string][]*types.NetworkRouter, error) CreateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) DeleteRouter(ctx context.Context, accountID, userID, networkID, routerID string) error DeleteRouterInTransaction(ctx context.Context, transaction store.Store, accountID, userID, networkID, routerID string) (func(), error) } type managerImpl struct { store store.Store permissionsManager permissions.Manager accountManager s.AccountManager } type mockManager struct { } func NewManager(store store.Store, permissionsManager permissions.Manager, accountManager s.AccountManager) Manager { return &managerImpl{ store: store, permissionsManager: permissionsManager, accountManager: accountManager, } } func (m *managerImpl) GetAllRoutersInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkRouter, error) { ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read) if err != nil { return nil, status.NewPermissionValidationError(err) } if !ok { return nil, status.NewPermissionDeniedError() } return m.store.GetNetworkRoutersByNetID(ctx, store.LockingStrengthShare, accountID, networkID) } func (m *managerImpl) GetAllRoutersInAccount(ctx context.Context, accountID, userID string) (map[string][]*types.NetworkRouter, error) { ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read) if err != nil { return nil, status.NewPermissionValidationError(err) } if !ok { return nil, status.NewPermissionDeniedError() } routers, err := m.store.GetNetworkRoutersByAccountID(ctx, store.LockingStrengthShare, accountID) if err != nil { return nil, fmt.Errorf("failed to get network routers: %w", err) } routersMap := make(map[string][]*types.NetworkRouter) for _, router := range routers { routersMap[router.NetworkID] = append(routersMap[router.NetworkID], router) } return routersMap, nil } func (m *managerImpl) CreateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) { ok, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, permissions.Networks, permissions.Write) if err != nil { return nil, status.NewPermissionValidationError(err) } if !ok { return nil, status.NewPermissionDeniedError() } unlock := m.store.AcquireWriteLockByUID(ctx, router.AccountID) defer unlock() var network *networkTypes.Network err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error { network, err = transaction.GetNetworkByID(ctx, store.LockingStrengthShare, router.AccountID, router.NetworkID) if err != nil { return fmt.Errorf("failed to get network: %w", err) } if network.ID != router.NetworkID { return status.NewNetworkNotFoundError(router.NetworkID) } router.ID = xid.New().String() err = transaction.SaveNetworkRouter(ctx, store.LockingStrengthUpdate, router) if err != nil { return fmt.Errorf("failed to create network router: %w", err) } err = transaction.IncrementNetworkSerial(ctx, store.LockingStrengthUpdate, router.AccountID) if err != nil { return fmt.Errorf("failed to increment network serial: %w", err) } return nil }) if err != nil { return nil, err } m.accountManager.StoreEvent(ctx, userID, router.ID, router.AccountID, activity.NetworkRouterCreated, router.EventMeta(network)) go m.accountManager.UpdateAccountPeers(ctx, router.AccountID) return router, nil } func (m *managerImpl) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) { ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read) if err != nil { return nil, status.NewPermissionValidationError(err) } if !ok { return nil, status.NewPermissionDeniedError() } router, err := m.store.GetNetworkRouterByID(ctx, store.LockingStrengthShare, accountID, routerID) if err != nil { return nil, fmt.Errorf("failed to get network router: %w", err) } if router.NetworkID != networkID { return nil, errors.New("router not part of network") } return router, nil } func (m *managerImpl) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) { ok, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, permissions.Networks, permissions.Write) if err != nil { return nil, status.NewPermissionValidationError(err) } if !ok { return nil, status.NewPermissionDeniedError() } unlock := m.store.AcquireWriteLockByUID(ctx, router.AccountID) defer unlock() var network *networkTypes.Network err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error { network, err = transaction.GetNetworkByID(ctx, store.LockingStrengthShare, router.AccountID, router.NetworkID) if err != nil { return fmt.Errorf("failed to get network: %w", err) } if network.ID != router.NetworkID { return status.NewRouterNotPartOfNetworkError(router.ID, router.NetworkID) } err = transaction.SaveNetworkRouter(ctx, store.LockingStrengthUpdate, router) if err != nil { return fmt.Errorf("failed to update network router: %w", err) } err = transaction.IncrementNetworkSerial(ctx, store.LockingStrengthUpdate, router.AccountID) if err != nil { return fmt.Errorf("failed to increment network serial: %w", err) } return nil }) if err != nil { return nil, err } m.accountManager.StoreEvent(ctx, userID, router.ID, router.AccountID, activity.NetworkRouterUpdated, router.EventMeta(network)) go m.accountManager.UpdateAccountPeers(ctx, router.AccountID) return router, nil } func (m *managerImpl) DeleteRouter(ctx context.Context, accountID, userID, networkID, routerID string) error { ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Write) if err != nil { return status.NewPermissionValidationError(err) } if !ok { return status.NewPermissionDeniedError() } unlock := m.store.AcquireWriteLockByUID(ctx, accountID) defer unlock() var event func() err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error { event, err = m.DeleteRouterInTransaction(ctx, transaction, accountID, userID, networkID, routerID) if err != nil { return fmt.Errorf("failed to delete network router: %w", err) } err = transaction.IncrementNetworkSerial(ctx, store.LockingStrengthUpdate, accountID) if err != nil { return fmt.Errorf("failed to increment network serial: %w", err) } return nil }) if err != nil { return err } event() go m.accountManager.UpdateAccountPeers(ctx, accountID) return nil } func (m *managerImpl) DeleteRouterInTransaction(ctx context.Context, transaction store.Store, accountID, userID, networkID, routerID string) (func(), error) { network, err := transaction.GetNetworkByID(ctx, store.LockingStrengthShare, accountID, networkID) if err != nil { return nil, fmt.Errorf("failed to get network: %w", err) } router, err := transaction.GetNetworkRouterByID(ctx, store.LockingStrengthUpdate, accountID, routerID) if err != nil { return nil, fmt.Errorf("failed to get network router: %w", err) } if router.NetworkID != networkID { return nil, status.NewRouterNotPartOfNetworkError(routerID, networkID) } err = transaction.DeleteNetworkRouter(ctx, store.LockingStrengthUpdate, accountID, routerID) if err != nil { return nil, fmt.Errorf("failed to delete network router: %w", err) } event := func() { m.accountManager.StoreEvent(ctx, userID, routerID, accountID, activity.NetworkRouterDeleted, router.EventMeta(network)) } return event, nil } func NewManagerMock() Manager { return &mockManager{} } func (m *mockManager) GetAllRoutersInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkRouter, error) { return []*types.NetworkRouter{}, nil } func (m *mockManager) GetAllRoutersInAccount(ctx context.Context, accountID, userID string) (map[string][]*types.NetworkRouter, error) { return map[string][]*types.NetworkRouter{}, nil } func (m *mockManager) CreateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) { return router, nil } func (m *mockManager) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) { return &types.NetworkRouter{}, nil } func (m *mockManager) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) { return router, nil } func (m *mockManager) DeleteRouter(ctx context.Context, accountID, userID, networkID, routerID string) error { return nil } func (m *mockManager) DeleteRouterInTransaction(ctx context.Context, transaction store.Store, accountID, userID, networkID, routerID string) (func(), error) { return func() {}, nil }