Merge branch 'feature/user-info-with-role-permissions' into feature/users-roles-endpoint

This commit is contained in:
Pedro Costa
2025-04-29 19:27:39 +01:00
8 changed files with 82 additions and 46 deletions
+1 -1
View File
@@ -116,5 +116,5 @@ type Manager interface {
CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error) CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error)
UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error) UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error)
GetOwnerInfo(ctx context.Context, accountId string) (*types.UserInfo, error) GetOwnerInfo(ctx context.Context, accountId string) (*types.UserInfo, error)
GetCurrentUserInfo(ctx context.Context, accountID, userID string) (*users.UserInfoWithPermissions, error) GetCurrentUserInfo(ctx context.Context, userAuth nbcontext.UserAuth) (*users.UserInfoWithPermissions, error)
} }
@@ -278,15 +278,13 @@ func (h *handler) getCurrentUser(w http.ResponseWriter, r *http.Request) {
return return
} }
accountID, userID := userAuth.AccountId, userAuth.UserId user, err := h.accountManager.GetCurrentUserInfo(ctx, userAuth)
user, err := h.accountManager.GetCurrentUserInfo(ctx, accountID, userID)
if err != nil { if err != nil {
util.WriteError(r.Context(), err, w) util.WriteError(r.Context(), err, w)
return return
} }
util.WriteJSONObject(r.Context(), w, toUserWithPermissionsResponse(user, userID)) util.WriteJSONObject(r.Context(), w, toUserWithPermissionsResponse(user, userAuth.UserId))
} }
func (h *handler) getRoles(w http.ResponseWriter, r *http.Request) { func (h *handler) getRoles(w http.ResponseWriter, r *http.Request) {
@@ -128,8 +128,8 @@ func initUsersTestData() *handler {
return nil return nil
}, },
GetCurrentUserInfoFunc: func(ctx context.Context, accountID, userID string) (*users.UserInfoWithPermissions, error) { GetCurrentUserInfoFunc: func(ctx context.Context, userAuth nbcontext.UserAuth) (*users.UserInfoWithPermissions, error) {
switch userID { switch userAuth.UserId {
case "not-found": case "not-found":
return nil, status.NewUserNotFoundError("not-found") return nil, status.NewUserNotFoundError("not-found")
case "not-of-account": case "not-of-account":
@@ -200,7 +200,7 @@ func initUsersTestData() *handler {
}, nil }, nil
} }
return nil, fmt.Errorf("user id %s not handled", userID) return nil, fmt.Errorf("user id %s not handled", userAuth.UserId)
}, },
}, },
} }
@@ -116,7 +116,7 @@ type MockAccountManager struct {
CreateAccountByPrivateDomainFunc func(ctx context.Context, initiatorId, domain string) (*types.Account, error) CreateAccountByPrivateDomainFunc func(ctx context.Context, initiatorId, domain string) (*types.Account, error)
UpdateToPrimaryAccountFunc func(ctx context.Context, accountId string) (*types.Account, error) UpdateToPrimaryAccountFunc func(ctx context.Context, accountId string) (*types.Account, error)
GetOwnerInfoFunc func(ctx context.Context, accountID string) (*types.UserInfo, error) GetOwnerInfoFunc func(ctx context.Context, accountID string) (*types.UserInfo, error)
GetCurrentUserInfoFunc func(ctx context.Context, accountID, userID string) (*users.UserInfoWithPermissions, error) GetCurrentUserInfoFunc func(ctx context.Context, userAuth nbcontext.UserAuth) (*users.UserInfoWithPermissions, error)
GetAccountMetaFunc func(ctx context.Context, accountID, userID string) (*types.AccountMeta, error) GetAccountMetaFunc func(ctx context.Context, accountID, userID string) (*types.AccountMeta, error)
} }
@@ -883,9 +883,9 @@ func (am *MockAccountManager) GetOwnerInfo(ctx context.Context, accountId string
return nil, status.Errorf(codes.Unimplemented, "method GetOwnerInfo is not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetOwnerInfo is not implemented")
} }
func (am *MockAccountManager) GetCurrentUserInfo(ctx context.Context, accountID, userID string) (*users.UserInfoWithPermissions, error) { func (am *MockAccountManager) GetCurrentUserInfo(ctx context.Context, userAuth nbcontext.UserAuth) (*users.UserInfoWithPermissions, error) {
if am.GetCurrentUserInfoFunc != nil { if am.GetCurrentUserInfoFunc != nil {
return am.GetCurrentUserInfoFunc(ctx, accountID, userID) return am.GetCurrentUserInfoFunc(ctx, userAuth)
} }
return nil, status.Errorf(codes.Unimplemented, "method GetCurrentUserInfo is not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetCurrentUserInfo is not implemented")
} }
+1 -1
View File
@@ -59,7 +59,7 @@ func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID
return nil, fmt.Errorf("failed to get account settings: %w", err) return nil, fmt.Errorf("failed to get account settings: %w", err)
} }
if settings.RegularUsersViewBlocked { if user.IsRestrictable() && settings.RegularUsersViewBlocked {
return []*nbpeer.Peer{}, nil return []*nbpeer.Peer{}, nil
} }
+5 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/activity"
nbContext "github.com/netbirdio/netbird/management/server/context" nbContext "github.com/netbirdio/netbird/management/server/context"
nbcontext "github.com/netbirdio/netbird/management/server/context"
"github.com/netbirdio/netbird/management/server/idp" "github.com/netbirdio/netbird/management/server/idp"
nbpeer "github.com/netbirdio/netbird/management/server/peer" nbpeer "github.com/netbirdio/netbird/management/server/peer"
"github.com/netbirdio/netbird/management/server/permissions/modules" "github.com/netbirdio/netbird/management/server/permissions/modules"
@@ -1217,7 +1218,9 @@ func validateUserInvite(invite *types.UserInfo) error {
} }
// GetCurrentUserInfo retrieves the account's current user info and permissions // GetCurrentUserInfo retrieves the account's current user info and permissions
func (am *DefaultAccountManager) GetCurrentUserInfo(ctx context.Context, accountID, userID string) (*users.UserInfoWithPermissions, error) { func (am *DefaultAccountManager) GetCurrentUserInfo(ctx context.Context, userAuth nbcontext.UserAuth) (*users.UserInfoWithPermissions, error) {
accountID, userID := userAuth.AccountId, userAuth.UserId
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID) user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1247,7 +1250,7 @@ func (am *DefaultAccountManager) GetCurrentUserInfo(ctx context.Context, account
userWithPermissions := &users.UserInfoWithPermissions{ userWithPermissions := &users.UserInfoWithPermissions{
UserInfo: userInfo, UserInfo: userInfo,
Restricted: user.IsRestrictable() && settings.RegularUsersViewBlocked, Restricted: !userAuth.IsChild && user.IsRestrictable() && settings.RegularUsersViewBlocked,
} }
permissions, err := am.permissionsManager.GetPermissionsByRole(ctx, user.Role) permissions, err := am.permissionsManager.GetPermissionsByRole(ctx, user.Role)
+37 -26
View File
@@ -1573,39 +1573,33 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
tt := []struct { tt := []struct {
name string name string
accountId string userAuth nbcontext.UserAuth
userId string
expectedErr error expectedErr error
expectedResult *users.UserInfoWithPermissions expectedResult *users.UserInfoWithPermissions
}{ }{
{ {
name: "not found", name: "not found",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "not-found"},
userId: "not-found",
expectedErr: status.NewUserNotFoundError("not-found"), expectedErr: status.NewUserNotFoundError("not-found"),
}, },
{ {
name: "not part of account", name: "not part of account",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "account2Owner"},
userId: "account2Owner",
expectedErr: status.NewUserNotPartOfAccountError(), expectedErr: status.NewUserNotPartOfAccountError(),
}, },
{ {
name: "blocked", name: "blocked",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "blocked-user"},
userId: "blocked-user",
expectedErr: status.NewUserBlockedError(), expectedErr: status.NewUserBlockedError(),
}, },
{ {
name: "service user", name: "service user",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "service-user"},
userId: "service-user",
expectedErr: status.NewPermissionDeniedError(), expectedErr: status.NewPermissionDeniedError(),
}, },
{ {
name: "owner user", name: "owner user",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "account1Owner"},
userId: "account1Owner",
expectedResult: &users.UserInfoWithPermissions{ expectedResult: &users.UserInfoWithPermissions{
UserInfo: &types.UserInfo{ UserInfo: &types.UserInfo{
ID: "account1Owner", ID: "account1Owner",
@@ -1624,9 +1618,8 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
}, },
}, },
{ {
name: "regular user", name: "regular user",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "regular-user"},
userId: "regular-user",
expectedResult: &users.UserInfoWithPermissions{ expectedResult: &users.UserInfoWithPermissions{
UserInfo: &types.UserInfo{ UserInfo: &types.UserInfo{
ID: "regular-user", ID: "regular-user",
@@ -1644,9 +1637,8 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
}, },
}, },
{ {
name: "admin user", name: "admin user",
accountId: account1.Id, userAuth: nbcontext.UserAuth{AccountId: account1.Id, UserId: "admin-user"},
userId: "admin-user",
expectedResult: &users.UserInfoWithPermissions{ expectedResult: &users.UserInfoWithPermissions{
UserInfo: &types.UserInfo{ UserInfo: &types.UserInfo{
ID: "admin-user", ID: "admin-user",
@@ -1664,9 +1656,8 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
}, },
}, },
{ {
name: "settings blocked regular user", name: "settings blocked regular user",
accountId: account2.Id, userAuth: nbcontext.UserAuth{AccountId: account2.Id, UserId: "settings-blocked-user"},
userId: "settings-blocked-user",
expectedResult: &users.UserInfoWithPermissions{ expectedResult: &users.UserInfoWithPermissions{
UserInfo: &types.UserInfo{ UserInfo: &types.UserInfo{
ID: "settings-blocked-user", ID: "settings-blocked-user",
@@ -1684,10 +1675,30 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
Restricted: true, Restricted: true,
}, },
}, },
{ {
name: "settings blocked owner user", name: "settings blocked regular user child account",
accountId: account2.Id, userAuth: nbcontext.UserAuth{AccountId: account2.Id, UserId: "settings-blocked-user", IsChild: true},
userId: "account2Owner", expectedResult: &users.UserInfoWithPermissions{
UserInfo: &types.UserInfo{
ID: "settings-blocked-user",
Name: "",
Role: "user",
Status: "active",
IsServiceUser: false,
IsBlocked: false,
NonDeletable: false,
LastLogin: time.Time{},
Issued: "api",
IntegrationReference: integration_reference.IntegrationReference{},
},
Permissions: mergeRolePermissions(roles.User),
Restricted: false,
},
},
{
name: "settings blocked owner user",
userAuth: nbcontext.UserAuth{AccountId: account2.Id, UserId: "account2Owner"},
expectedResult: &users.UserInfoWithPermissions{ expectedResult: &users.UserInfoWithPermissions{
UserInfo: &types.UserInfo{ UserInfo: &types.UserInfo{
ID: "account2Owner", ID: "account2Owner",
@@ -1709,7 +1720,7 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
for _, tc := range tt { for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
result, err := am.GetCurrentUserInfo(context.Background(), tc.accountId, tc.userId) result, err := am.GetCurrentUserInfo(context.Background(), tc.userAuth)
if tc.expectedErr != nil { if tc.expectedErr != nil {
assert.Equal(t, err, tc.expectedErr) assert.Equal(t, err, tc.expectedErr)
+29 -5
View File
@@ -199,6 +199,21 @@ install_native_binaries() {
fi fi
} }
# Handle macOS .pkg installer
install_pkg() {
case "$(uname -m)" in
x86_64) ARCH="amd64" ;;
arm64|aarch64) ARCH="arm64" ;;
*) echo "Unsupported macOS arch: $(uname -m)" >&2; exit 1 ;;
esac
PKG_URL=$(curl -sIL -o /dev/null -w '%{url_effective}' "https://pkgs.netbird.io/macos/${ARCH}")
echo "Downloading NetBird macOS installer from https://pkgs.netbird.io/macos/${ARCH}"
curl -fsSL -o /tmp/netbird.pkg "${PKG_URL}"
${SUDO} installer -pkg /tmp/netbird.pkg -target /
rm -f /tmp/netbird.pkg
}
check_use_bin_variable() { check_use_bin_variable() {
if [ "${USE_BIN_INSTALL}-x" = "true-x" ]; then if [ "${USE_BIN_INSTALL}-x" = "true-x" ]; then
echo "The installation will be performed using binary files" echo "The installation will be performed using binary files"
@@ -265,6 +280,16 @@ install_netbird() {
${SUDO} pacman -Syy ${SUDO} pacman -Syy
add_aur_repo add_aur_repo
;; ;;
pkg)
# Check if the package is already installed
if [ -f /Library/Receipts/netbird.pkg ]; then
echo "NetBird is already installed. Please remove it before proceeding."
exit 1
fi
# Install the package
install_pkg
;;
brew) brew)
# Remove Netbird if it had been installed using Homebrew before # Remove Netbird if it had been installed using Homebrew before
if brew ls --versions netbird >/dev/null 2>&1; then if brew ls --versions netbird >/dev/null 2>&1; then
@@ -274,7 +299,7 @@ install_netbird() {
netbird service stop netbird service stop
netbird service uninstall netbird service uninstall
# Unlik the app # Unlink the app
brew unlink netbird brew unlink netbird
fi fi
@@ -312,7 +337,7 @@ install_netbird() {
echo "package_manager=$PACKAGE_MANAGER" | ${SUDO} tee "$CONFIG_FILE" > /dev/null echo "package_manager=$PACKAGE_MANAGER" | ${SUDO} tee "$CONFIG_FILE" > /dev/null
# Load and start netbird service # Load and start netbird service
if [ "$PACKAGE_MANAGER" != "rpm-ostree" ]; then if [ "$PACKAGE_MANAGER" != "rpm-ostree" ] && [ "$PACKAGE_MANAGER" != "pkg" ]; then
if ! ${SUDO} netbird service install 2>&1; then if ! ${SUDO} netbird service install 2>&1; then
echo "NetBird service has already been loaded" echo "NetBird service has already been loaded"
fi fi
@@ -451,9 +476,8 @@ if type uname >/dev/null 2>&1; then
# Check the availability of a compatible package manager # Check the availability of a compatible package manager
if check_use_bin_variable; then if check_use_bin_variable; then
PACKAGE_MANAGER="bin" PACKAGE_MANAGER="bin"
elif [ -x "$(command -v brew)" ]; then else
PACKAGE_MANAGER="brew" PACKAGE_MANAGER="pkg"
echo "The installation will be performed using brew package manager"
fi fi
;; ;;
esac esac