package permissions //go:generate go run github.com/golang/mock/mockgen -package permissions -destination=manager_mock.go -source=./manager.go -build_flags=-mod=mod import ( "context" "github.com/netbirdio/netbird/management/server/status" "management/internal/modules/users/types" "management/internal/shared/activity" "management/internal/shared/db" "management/internal/shared/permissions/modules" "management/internal/shared/permissions/operations" "management/internal/shared/permissions/roles" "management/pkg/logging" ) var log = logging.LoggerForThisPackage() type Manager interface { ValidateUserPermissions(ctx context.Context, accountID, userID string, module modules.Module, operation operations.Operation) (bool, error) ValidateRoleModuleAccess(ctx context.Context, accountID string, role roles.RolePermissions, module modules.Module, operation operations.Operation) bool ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error Init(userManager userManager) } type userManager interface { GetUserByID(ctx context.Context, tx db.Transaction, strength db.LockingStrength, id string) (*types.User, error) } type managerImpl struct { userManager userManager } func NewManager() Manager { return &managerImpl{} } func (m *managerImpl) Init(userManager userManager) { m.userManager = userManager } func (m *managerImpl) ValidateUserPermissions( ctx context.Context, accountID string, userID string, module modules.Module, operation operations.Operation, ) (bool, error) { if userID == activity.SystemInitiator { return true, nil } user, err := m.userManager.GetUserByID(ctx, nil, db.LockingStrengthShare, userID) if err != nil { return false, err } if user == nil { return false, status.NewUserNotFoundError(userID) } if user.IsBlocked() { return false, status.NewUserBlockedError() } if err := m.ValidateAccountAccess(ctx, accountID, user, false); err != nil { return false, err } if operation == operations.Read && user.IsServiceUser { return true, nil // this should be replaced by proper granular access role } role, ok := roles.RolesMap[user.Role] if !ok { return false, status.NewUserRoleNotFoundError(string(user.Role)) } return m.ValidateRoleModuleAccess(ctx, accountID, role, module, operation), nil } func (m *managerImpl) ValidateRoleModuleAccess( ctx context.Context, accountID string, role roles.RolePermissions, module modules.Module, operation operations.Operation, ) bool { if permissions, ok := role.Permissions[module]; ok { if allowed, exists := permissions[operation]; exists { return allowed } log.WithContext(ctx).Tracef("operation %s not found on module %s for role %s", operation, module, role.Role) return false } return role.AutoAllowNew[operation] } func (m *managerImpl) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error { if user.AccountID != accountID { return status.NewUserNotPartOfAccountError() } return nil }