mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-21 23:53:14 +01:00
[management] Refactor setup key to use store methods (#2861)
* Refactor setup key handling to use store methods Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * add lock to get account groups Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * add check for regular user Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * get only required groups for auto-group validation Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * add account lock and return auto groups map on validation Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * fix missing group removed from setup key activity Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * Remove context from DB queries Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * Add user permission check and add setup events into events to store slice Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * Retrieve all groups once during setup key auto-group validation Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * Fix lint Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> * Fix sonar Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com> --------- Signed-off-by: bcmmbaga <bethuelmbaga12@gmail.com>
This commit is contained in:
parent
e0bed2b0fb
commit
6cb697eed6
@ -2029,7 +2029,7 @@ func (am *DefaultAccountManager) syncJWTGroups(ctx context.Context, accountID st
|
|||||||
return fmt.Errorf("error getting user: %w", err)
|
return fmt.Errorf("error getting user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
groups, err := transaction.GetAccountGroups(ctx, accountID)
|
groups, err := transaction.GetAccountGroups(ctx, LockingStrengthShare, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting account groups: %w", err)
|
return fmt.Errorf("error getting account groups: %w", err)
|
||||||
}
|
}
|
||||||
@ -2059,7 +2059,7 @@ func (am *DefaultAccountManager) syncJWTGroups(ctx context.Context, accountID st
|
|||||||
|
|
||||||
// Propagate changes to peers if group propagation is enabled
|
// Propagate changes to peers if group propagation is enabled
|
||||||
if settings.GroupsPropagationEnabled {
|
if settings.GroupsPropagationEnabled {
|
||||||
groups, err = transaction.GetAccountGroups(ctx, accountID)
|
groups, err = transaction.GetAccountGroups(ctx, LockingStrengthShare, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting account groups: %w", err)
|
return fmt.Errorf("error getting account groups: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -2773,7 +2773,7 @@ func TestAccount_SetJWTGroups(t *testing.T) {
|
|||||||
err = manager.syncJWTGroups(context.Background(), "accountID", claims)
|
err = manager.syncJWTGroups(context.Background(), "accountID", claims)
|
||||||
assert.NoError(t, err, "unable to sync jwt groups")
|
assert.NoError(t, err, "unable to sync jwt groups")
|
||||||
|
|
||||||
groups, err := manager.Store.GetAccountGroups(context.Background(), "accountID")
|
groups, err := manager.Store.GetAccountGroups(context.Background(), LockingStrengthShare, "accountID")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, groups, 3, "new group3 should be added")
|
assert.Len(t, groups, 3, "new group3 should be added")
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ func (am *DefaultAccountManager) GetAllGroups(ctx context.Context, accountID, us
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountGroups(ctx, accountID)
|
return am.Store.GetAccountGroups(ctx, LockingStrengthShare, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroupByName filters all groups in an account by name and returns the one with the most peers
|
// GetGroupByName filters all groups in an account by name and returns the one with the most peers
|
||||||
|
@ -49,3 +49,8 @@ func (g *Group) Copy() *Group {
|
|||||||
func (g *Group) HasPeers() bool {
|
func (g *Group) HasPeers() bool {
|
||||||
return len(g.Peers) > 0
|
return len(g.Peers) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsGroupAll checks if the group is a default "All" group.
|
||||||
|
func (g *Group) IsGroupAll() bool {
|
||||||
|
return g.Name == "All"
|
||||||
|
}
|
||||||
|
@ -765,7 +765,7 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login PeerLogin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
groups, err := am.Store.GetAccountGroups(ctx, accountID)
|
groups, err := am.Store.GetAccountGroups(ctx, LockingStrengthShare, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,17 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
b64 "encoding/base64"
|
b64 "encoding/base64"
|
||||||
"fmt"
|
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -229,32 +228,43 @@ func (am *DefaultAccountManager) CreateSetupKey(ctx context.Context, accountID s
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(ctx, accountID)
|
user, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateSetupKeyAutoGroups(account, autoGroups); err != nil {
|
if user.AccountID != accountID {
|
||||||
return nil, err
|
return nil, status.NewUserNotPartOfAccountError()
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKey, plainKey := GenerateSetupKey(keyName, keyType, expiresIn, autoGroups, usageLimit, ephemeral)
|
if user.IsRegularUser() {
|
||||||
account.SetupKeys[setupKey.Key] = setupKey
|
return nil, status.NewAdminPermissionError()
|
||||||
err = am.Store.SaveAccount(ctx, account)
|
}
|
||||||
|
|
||||||
|
var setupKey *SetupKey
|
||||||
|
var plainKey string
|
||||||
|
var eventsToStore []func()
|
||||||
|
|
||||||
|
err = am.Store.ExecuteInTransaction(ctx, func(transaction Store) error {
|
||||||
|
if err = validateSetupKeyAutoGroups(ctx, transaction, accountID, autoGroups); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
setupKey, plainKey = GenerateSetupKey(keyName, keyType, expiresIn, autoGroups, usageLimit, ephemeral)
|
||||||
|
setupKey.AccountID = accountID
|
||||||
|
|
||||||
|
events := am.prepareSetupKeyEvents(ctx, transaction, accountID, userID, autoGroups, nil, setupKey)
|
||||||
|
eventsToStore = append(eventsToStore, events...)
|
||||||
|
|
||||||
|
return transaction.SaveSetupKey(ctx, LockingStrengthUpdate, setupKey)
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(status.Internal, "failed adding account key")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
am.StoreEvent(ctx, userID, setupKey.Id, accountID, activity.SetupKeyCreated, setupKey.EventMeta())
|
am.StoreEvent(ctx, userID, setupKey.Id, accountID, activity.SetupKeyCreated, setupKey.EventMeta())
|
||||||
|
for _, storeEvent := range eventsToStore {
|
||||||
for _, g := range setupKey.AutoGroups {
|
storeEvent()
|
||||||
group := account.GetGroup(g)
|
|
||||||
if group != nil {
|
|
||||||
am.StoreEvent(ctx, userID, setupKey.Id, accountID, activity.GroupAddedToSetupKey,
|
|
||||||
map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": setupKey.Name})
|
|
||||||
} else {
|
|
||||||
log.WithContext(ctx).Errorf("group %s not found while saving setup key activity event of account %s", g, account.Id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the creation return the plain key to the caller
|
// for the creation return the plain key to the caller
|
||||||
@ -268,43 +278,56 @@ func (am *DefaultAccountManager) CreateSetupKey(ctx context.Context, accountID s
|
|||||||
// (e.g. the key itself, creation date, ID, etc).
|
// (e.g. the key itself, creation date, ID, etc).
|
||||||
// These properties are overwritten: Name, AutoGroups, Revoked. The rest is copied from the existing key.
|
// These properties are overwritten: Name, AutoGroups, Revoked. The rest is copied from the existing key.
|
||||||
func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID string, keyToSave *SetupKey, userID string) (*SetupKey, error) {
|
func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID string, keyToSave *SetupKey, userID string) (*SetupKey, error) {
|
||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
|
||||||
defer unlock()
|
|
||||||
|
|
||||||
if keyToSave == nil {
|
if keyToSave == nil {
|
||||||
return nil, status.Errorf(status.InvalidArgument, "provided setup key to update is nil")
|
return nil, status.Errorf(status.InvalidArgument, "provided setup key to update is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
user, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.AccountID != accountID {
|
||||||
|
return nil, status.NewUserNotPartOfAccountError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.IsRegularUser() {
|
||||||
|
return nil, status.NewAdminPermissionError()
|
||||||
|
}
|
||||||
|
|
||||||
var oldKey *SetupKey
|
var oldKey *SetupKey
|
||||||
for _, key := range account.SetupKeys {
|
var newKey *SetupKey
|
||||||
if key.Id == keyToSave.Id {
|
var eventsToStore []func()
|
||||||
oldKey = key.Copy()
|
|
||||||
break
|
err = am.Store.ExecuteInTransaction(ctx, func(transaction Store) error {
|
||||||
|
if err = validateSetupKeyAutoGroups(ctx, transaction, accountID, keyToSave.AutoGroups); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if oldKey == nil {
|
|
||||||
return nil, status.Errorf(status.NotFound, "setup key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateSetupKeyAutoGroups(account, keyToSave.AutoGroups); err != nil {
|
oldKey, err = transaction.GetSetupKeyByID(ctx, LockingStrengthShare, accountID, keyToSave.Id)
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// only auto groups, revoked status, and name can be updated for now
|
// only auto groups, revoked status, and name can be updated for now
|
||||||
newKey := oldKey.Copy()
|
newKey = oldKey.Copy()
|
||||||
newKey.Name = keyToSave.Name
|
newKey.Name = keyToSave.Name
|
||||||
newKey.AutoGroups = keyToSave.AutoGroups
|
newKey.AutoGroups = keyToSave.AutoGroups
|
||||||
newKey.Revoked = keyToSave.Revoked
|
newKey.Revoked = keyToSave.Revoked
|
||||||
newKey.UpdatedAt = time.Now().UTC()
|
newKey.UpdatedAt = time.Now().UTC()
|
||||||
|
|
||||||
account.SetupKeys[newKey.Key] = newKey
|
addedGroups := difference(newKey.AutoGroups, oldKey.AutoGroups)
|
||||||
|
removedGroups := difference(oldKey.AutoGroups, newKey.AutoGroups)
|
||||||
|
|
||||||
if err = am.Store.SaveAccount(ctx, account); err != nil {
|
events := am.prepareSetupKeyEvents(ctx, transaction, accountID, userID, addedGroups, removedGroups, oldKey)
|
||||||
|
eventsToStore = append(eventsToStore, events...)
|
||||||
|
|
||||||
|
return transaction.SaveSetupKey(ctx, LockingStrengthUpdate, newKey)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,30 +335,9 @@ func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID str
|
|||||||
am.StoreEvent(ctx, userID, newKey.Id, accountID, activity.SetupKeyRevoked, newKey.EventMeta())
|
am.StoreEvent(ctx, userID, newKey.Id, accountID, activity.SetupKeyRevoked, newKey.EventMeta())
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
for _, storeEvent := range eventsToStore {
|
||||||
addedGroups := difference(newKey.AutoGroups, oldKey.AutoGroups)
|
storeEvent()
|
||||||
removedGroups := difference(oldKey.AutoGroups, newKey.AutoGroups)
|
}
|
||||||
for _, g := range removedGroups {
|
|
||||||
group := account.GetGroup(g)
|
|
||||||
if group != nil {
|
|
||||||
am.StoreEvent(ctx, userID, oldKey.Id, accountID, activity.GroupRemovedFromSetupKey,
|
|
||||||
map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": newKey.Name})
|
|
||||||
} else {
|
|
||||||
log.WithContext(ctx).Errorf("group %s not found while saving setup key activity event of account %s", g, account.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, g := range addedGroups {
|
|
||||||
group := account.GetGroup(g)
|
|
||||||
if group != nil {
|
|
||||||
am.StoreEvent(ctx, userID, oldKey.Id, accountID, activity.GroupAddedToSetupKey,
|
|
||||||
map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": newKey.Name})
|
|
||||||
} else {
|
|
||||||
log.WithContext(ctx).Errorf("group %s not found while saving setup key activity event of account %s", g, account.Id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return newKey, nil
|
return newKey, nil
|
||||||
}
|
}
|
||||||
@ -347,16 +349,15 @@ func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, u
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.IsAdminOrServiceUser() || user.AccountID != accountID {
|
if user.AccountID != accountID {
|
||||||
return nil, status.NewUnauthorizedToViewSetupKeysError()
|
return nil, status.NewUserNotPartOfAccountError()
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKeys, err := am.Store.GetAccountSetupKeys(ctx, LockingStrengthShare, accountID)
|
if user.IsRegularUser() {
|
||||||
if err != nil {
|
return nil, status.NewAdminPermissionError()
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return setupKeys, nil
|
return am.Store.GetAccountSetupKeys(ctx, LockingStrengthShare, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSetupKey looks up a SetupKey by KeyID, returns NotFound error if not found.
|
// GetSetupKey looks up a SetupKey by KeyID, returns NotFound error if not found.
|
||||||
@ -366,8 +367,12 @@ func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, use
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.IsAdminOrServiceUser() || user.AccountID != accountID {
|
if user.AccountID != accountID {
|
||||||
return nil, status.NewUnauthorizedToViewSetupKeysError()
|
return nil, status.NewUserNotPartOfAccountError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.IsRegularUser() {
|
||||||
|
return nil, status.NewAdminPermissionError()
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKey, err := am.Store.GetSetupKeyByID(ctx, LockingStrengthShare, keyID, accountID)
|
setupKey, err := am.Store.GetSetupKeyByID(ctx, LockingStrengthShare, keyID, accountID)
|
||||||
@ -387,21 +392,29 @@ func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, use
|
|||||||
func (am *DefaultAccountManager) DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error {
|
func (am *DefaultAccountManager) DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, userID)
|
user, err := am.Store.GetUserByUserID(ctx, LockingStrengthShare, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get user: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.IsAdminOrServiceUser() || user.AccountID != accountID {
|
if user.AccountID != accountID {
|
||||||
return status.NewUnauthorizedToViewSetupKeysError()
|
return status.NewUserNotPartOfAccountError()
|
||||||
}
|
}
|
||||||
|
|
||||||
deletedSetupKey, err := am.Store.GetSetupKeyByID(ctx, LockingStrengthShare, keyID, accountID)
|
if user.IsRegularUser() {
|
||||||
|
return status.NewAdminPermissionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
var deletedSetupKey *SetupKey
|
||||||
|
|
||||||
|
err = am.Store.ExecuteInTransaction(ctx, func(transaction Store) error {
|
||||||
|
deletedSetupKey, err = transaction.GetSetupKeyByID(ctx, LockingStrengthShare, accountID, keyID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return transaction.DeleteSetupKey(ctx, LockingStrengthUpdate, accountID, keyID)
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get setup key: %w", err)
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
err = am.Store.DeleteSetupKey(ctx, accountID, keyID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to delete setup key: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
am.StoreEvent(ctx, userID, keyID, accountID, activity.SetupKeyDeleted, deletedSetupKey.EventMeta())
|
am.StoreEvent(ctx, userID, keyID, accountID, activity.SetupKeyDeleted, deletedSetupKey.EventMeta())
|
||||||
@ -409,15 +422,62 @@ func (am *DefaultAccountManager) DeleteSetupKey(ctx context.Context, accountID,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSetupKeyAutoGroups(account *Account, autoGroups []string) error {
|
func validateSetupKeyAutoGroups(ctx context.Context, transaction Store, accountID string, autoGroupIDs []string) error {
|
||||||
for _, group := range autoGroups {
|
groups, err := transaction.GetGroupsByIDs(ctx, LockingStrengthShare, accountID, autoGroupIDs)
|
||||||
g, ok := account.Groups[group]
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, groupID := range autoGroupIDs {
|
||||||
|
group, ok := groups[groupID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return status.Errorf(status.NotFound, "group %s doesn't exist", group)
|
return status.Errorf(status.NotFound, "group not found: %s", groupID)
|
||||||
}
|
}
|
||||||
if g.Name == "All" {
|
|
||||||
return status.Errorf(status.InvalidArgument, "can't add All group to the setup key")
|
if group.IsGroupAll() {
|
||||||
|
return status.Errorf(status.InvalidArgument, "can't add 'All' group to the setup key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepareSetupKeyEvents prepares a list of event functions to be stored.
|
||||||
|
func (am *DefaultAccountManager) prepareSetupKeyEvents(ctx context.Context, transaction Store, accountID, userID string, addedGroups, removedGroups []string, key *SetupKey) []func() {
|
||||||
|
var eventsToStore []func()
|
||||||
|
|
||||||
|
modifiedGroups := slices.Concat(addedGroups, removedGroups)
|
||||||
|
groups, err := transaction.GetGroupsByIDs(ctx, LockingStrengthShare, accountID, modifiedGroups)
|
||||||
|
if err != nil {
|
||||||
|
log.WithContext(ctx).Errorf("issue getting groups for setup key events: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range removedGroups {
|
||||||
|
group, ok := groups[g]
|
||||||
|
if !ok {
|
||||||
|
log.WithContext(ctx).Debugf("skipped adding group: %s GroupRemovedFromSetupKey activity: %v", g, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
eventsToStore = append(eventsToStore, func() {
|
||||||
|
meta := map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": key.Name}
|
||||||
|
am.StoreEvent(ctx, userID, key.Id, accountID, activity.GroupRemovedFromSetupKey, meta)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range addedGroups {
|
||||||
|
group, ok := groups[g]
|
||||||
|
if !ok {
|
||||||
|
log.WithContext(ctx).Debugf("skipped adding group: %s GroupAddedToSetupKey activity: %v", g, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
eventsToStore = append(eventsToStore, func() {
|
||||||
|
meta := map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": key.Name}
|
||||||
|
am.StoreEvent(ctx, userID, key.Id, accountID, activity.GroupAddedToSetupKey, meta)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventsToStore
|
||||||
|
}
|
||||||
|
@ -485,9 +485,10 @@ func (s *SqlStore) GetAccountBySetupKey(ctx context.Context, setupKey string) (*
|
|||||||
result := s.db.Select("account_id").First(&key, keyQueryCondition, setupKey)
|
result := s.db.Select("account_id").First(&key, keyQueryCondition, setupKey)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return nil, status.Errorf(status.NotFound, "account not found: index lookup failed")
|
return nil, status.NewSetupKeyNotFoundError(setupKey)
|
||||||
}
|
}
|
||||||
return nil, status.NewSetupKeyNotFoundError(result.Error)
|
log.WithContext(ctx).Errorf("failed to get account by setup key from store: %v", result.Error)
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get account by setup key from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
if key.AccountID == "" {
|
if key.AccountID == "" {
|
||||||
@ -568,15 +569,15 @@ func (s *SqlStore) GetAccountUsers(ctx context.Context, accountID string) ([]*Us
|
|||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) GetAccountGroups(ctx context.Context, accountID string) ([]*nbgroup.Group, error) {
|
func (s *SqlStore) GetAccountGroups(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*nbgroup.Group, error) {
|
||||||
var groups []*nbgroup.Group
|
var groups []*nbgroup.Group
|
||||||
result := s.db.Find(&groups, accountIDCondition, accountID)
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Find(&groups, accountIDCondition, accountID)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return nil, status.Errorf(status.NotFound, "accountID not found: index lookup failed")
|
return nil, status.Errorf(status.NotFound, "accountID not found: index lookup failed")
|
||||||
}
|
}
|
||||||
log.WithContext(ctx).Errorf("error when getting groups from the store: %s", result.Error)
|
log.WithContext(ctx).Errorf("failed to get account groups from the store: %s", result.Error)
|
||||||
return nil, status.Errorf(status.Internal, "issue getting groups from store")
|
return nil, status.Errorf(status.Internal, "failed to get account groups from the store")
|
||||||
}
|
}
|
||||||
|
|
||||||
return groups, nil
|
return groups, nil
|
||||||
@ -756,9 +757,10 @@ func (s *SqlStore) GetAccountIDBySetupKey(ctx context.Context, setupKey string)
|
|||||||
result := s.db.Model(&SetupKey{}).Select("account_id").Where(keyQueryCondition, setupKey).First(&accountID)
|
result := s.db.Model(&SetupKey{}).Select("account_id").Where(keyQueryCondition, setupKey).First(&accountID)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return "", status.Errorf(status.NotFound, "account not found: index lookup failed")
|
return "", status.NewSetupKeyNotFoundError(setupKey)
|
||||||
}
|
}
|
||||||
return "", status.NewSetupKeyNotFoundError(result.Error)
|
log.WithContext(ctx).Errorf("failed to get account ID by setup key from store: %v", result.Error)
|
||||||
|
return "", status.Errorf(status.Internal, "failed to get account ID by setup key from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
if accountID == "" {
|
if accountID == "" {
|
||||||
@ -986,9 +988,10 @@ func (s *SqlStore) GetSetupKeyBySecret(ctx context.Context, lockStrength Locking
|
|||||||
First(&setupKey, keyQueryCondition, key)
|
First(&setupKey, keyQueryCondition, key)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return nil, status.Errorf(status.NotFound, "setup key not found")
|
return nil, status.NewSetupKeyNotFoundError(key)
|
||||||
}
|
}
|
||||||
return nil, status.NewSetupKeyNotFoundError(result.Error)
|
log.WithContext(ctx).Errorf("failed to get setup key by secret from store: %v", result.Error)
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get setup key by secret from store")
|
||||||
}
|
}
|
||||||
return &setupKey, nil
|
return &setupKey, nil
|
||||||
}
|
}
|
||||||
@ -1006,7 +1009,7 @@ func (s *SqlStore) IncrementSetupKeyUsage(ctx context.Context, setupKeyID string
|
|||||||
}
|
}
|
||||||
|
|
||||||
if result.RowsAffected == 0 {
|
if result.RowsAffected == 0 {
|
||||||
return status.Errorf(status.NotFound, "setup key not found")
|
return status.NewSetupKeyNotFoundError(setupKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -1179,6 +1182,23 @@ func (s *SqlStore) GetGroupByName(ctx context.Context, lockStrength LockingStren
|
|||||||
return &group, nil
|
return &group, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGroupsByIDs retrieves groups by their IDs and account ID.
|
||||||
|
func (s *SqlStore) GetGroupsByIDs(ctx context.Context, lockStrength LockingStrength, accountID string, groupIDs []string) (map[string]*nbgroup.Group, error) {
|
||||||
|
var groups []*nbgroup.Group
|
||||||
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Find(&groups, "account_id = ? AND id in ?", accountID, groupIDs)
|
||||||
|
if result.Error != nil {
|
||||||
|
log.WithContext(ctx).Errorf("failed to get groups by ID's from the store: %s", result.Error)
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get groups by ID's from the store")
|
||||||
|
}
|
||||||
|
|
||||||
|
groupsMap := make(map[string]*nbgroup.Group)
|
||||||
|
for _, group := range groups {
|
||||||
|
groupsMap[group.ID] = group
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupsMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SaveGroup saves a group to the store.
|
// SaveGroup saves a group to the store.
|
||||||
func (s *SqlStore) SaveGroup(ctx context.Context, lockStrength LockingStrength, group *nbgroup.Group) error {
|
func (s *SqlStore) SaveGroup(ctx context.Context, lockStrength LockingStrength, group *nbgroup.Group) error {
|
||||||
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Save(group)
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Save(group)
|
||||||
@ -1220,12 +1240,57 @@ func (s *SqlStore) GetRouteByID(ctx context.Context, lockStrength LockingStrengt
|
|||||||
|
|
||||||
// GetAccountSetupKeys retrieves setup keys for an account.
|
// GetAccountSetupKeys retrieves setup keys for an account.
|
||||||
func (s *SqlStore) GetAccountSetupKeys(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*SetupKey, error) {
|
func (s *SqlStore) GetAccountSetupKeys(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*SetupKey, error) {
|
||||||
return getRecords[*SetupKey](s.db, lockStrength, accountID)
|
var setupKeys []*SetupKey
|
||||||
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).
|
||||||
|
Find(&setupKeys, accountIDCondition, accountID)
|
||||||
|
if err := result.Error; err != nil {
|
||||||
|
log.WithContext(ctx).Errorf("failed to get setup keys from the store: %s", err)
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get setup keys from store")
|
||||||
|
}
|
||||||
|
|
||||||
|
return setupKeys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSetupKeyByID retrieves a setup key by its ID and account ID.
|
// GetSetupKeyByID retrieves a setup key by its ID and account ID.
|
||||||
func (s *SqlStore) GetSetupKeyByID(ctx context.Context, lockStrength LockingStrength, setupKeyID string, accountID string) (*SetupKey, error) {
|
func (s *SqlStore) GetSetupKeyByID(ctx context.Context, lockStrength LockingStrength, accountID, setupKeyID string) (*SetupKey, error) {
|
||||||
return getRecordByID[SetupKey](s.db, lockStrength, setupKeyID, accountID)
|
var setupKey *SetupKey
|
||||||
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).
|
||||||
|
First(&setupKey, accountAndIDQueryCondition, accountID, setupKeyID)
|
||||||
|
if err := result.Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, status.NewSetupKeyNotFoundError(setupKeyID)
|
||||||
|
}
|
||||||
|
log.WithContext(ctx).Errorf("failed to get setup key from the store: %s", err)
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get setup key from store")
|
||||||
|
}
|
||||||
|
|
||||||
|
return setupKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveSetupKey saves a setup key to the database.
|
||||||
|
func (s *SqlStore) SaveSetupKey(ctx context.Context, lockStrength LockingStrength, setupKey *SetupKey) error {
|
||||||
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Save(setupKey)
|
||||||
|
if result.Error != nil {
|
||||||
|
log.WithContext(ctx).Errorf("failed to save setup key to store: %s", result.Error)
|
||||||
|
return status.Errorf(status.Internal, "failed to save setup key to store")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSetupKey deletes a setup key from the database.
|
||||||
|
func (s *SqlStore) DeleteSetupKey(ctx context.Context, lockStrength LockingStrength, accountID, keyID string) error {
|
||||||
|
result := s.db.Clauses(clause.Locking{Strength: string(lockStrength)}).Delete(&SetupKey{}, accountAndIDQueryCondition, accountID, keyID)
|
||||||
|
if result.Error != nil {
|
||||||
|
log.WithContext(ctx).Errorf("failed to delete setup key from store: %s", result.Error)
|
||||||
|
return status.Errorf(status.Internal, "failed to delete setup key from store")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return status.NewSetupKeyNotFoundError(keyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountNameServerGroups retrieves name server groups for an account.
|
// GetAccountNameServerGroups retrieves name server groups for an account.
|
||||||
@ -1238,10 +1303,6 @@ func (s *SqlStore) GetNameServerGroupByID(ctx context.Context, lockStrength Lock
|
|||||||
return getRecordByID[nbdns.NameServerGroup](s.db, lockStrength, nsGroupID, accountID)
|
return getRecordByID[nbdns.NameServerGroup](s.db, lockStrength, nsGroupID, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlStore) DeleteSetupKey(ctx context.Context, accountID, keyID string) error {
|
|
||||||
return deleteRecordByID[SetupKey](s.db, LockingStrengthUpdate, keyID, accountID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getRecords retrieves records from the database based on the account ID.
|
// getRecords retrieves records from the database based on the account ID.
|
||||||
func getRecords[T any](db *gorm.DB, lockStrength LockingStrength, accountID string) ([]T, error) {
|
func getRecords[T any](db *gorm.DB, lockStrength LockingStrength, accountID string) ([]T, error) {
|
||||||
var record []T
|
var record []T
|
||||||
@ -1274,21 +1335,3 @@ func getRecordByID[T any](db *gorm.DB, lockStrength LockingStrength, recordID, a
|
|||||||
}
|
}
|
||||||
return &record, nil
|
return &record, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteRecordByID deletes a record by its ID and account ID from the database.
|
|
||||||
func deleteRecordByID[T any](db *gorm.DB, lockStrength LockingStrength, recordID, accountID string) error {
|
|
||||||
var record T
|
|
||||||
result := db.Clauses(clause.Locking{Strength: string(lockStrength)}).Delete(record, accountAndIDQueryCondition, accountID, recordID)
|
|
||||||
if err := result.Error; err != nil {
|
|
||||||
parts := strings.Split(fmt.Sprintf("%T", record), ".")
|
|
||||||
recordType := parts[len(parts)-1]
|
|
||||||
|
|
||||||
return status.Errorf(status.Internal, "failed to delete %s from store: %v", recordType, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.RowsAffected == 0 {
|
|
||||||
return status.Errorf(status.NotFound, "record not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -1274,7 +1274,7 @@ func Test_DeleteSetupKeySuccessfully(t *testing.T) {
|
|||||||
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
setupKeyID := "A2C8E62B-38F5-4553-B31E-DD66C696CEBB"
|
setupKeyID := "A2C8E62B-38F5-4553-B31E-DD66C696CEBB"
|
||||||
|
|
||||||
err = store.DeleteSetupKey(context.Background(), accountID, setupKeyID)
|
err = store.DeleteSetupKey(context.Background(), LockingStrengthUpdate, accountID, setupKeyID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = store.GetSetupKeyByID(context.Background(), LockingStrengthShare, setupKeyID, accountID)
|
_, err = store.GetSetupKeyByID(context.Background(), LockingStrengthShare, setupKeyID, accountID)
|
||||||
@ -1290,6 +1290,6 @@ func Test_DeleteSetupKeyFailsForNonExistingKey(t *testing.T) {
|
|||||||
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
nonExistingKeyID := "non-existing-key-id"
|
nonExistingKeyID := "non-existing-key-id"
|
||||||
|
|
||||||
err = store.DeleteSetupKey(context.Background(), accountID, nonExistingKeyID)
|
err = store.DeleteSetupKey(context.Background(), LockingStrengthUpdate, accountID, nonExistingKeyID)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
@ -103,19 +103,29 @@ func NewPeerLoginExpiredError() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSetupKeyNotFoundError creates a new Error with NotFound type for a missing setup key
|
// NewSetupKeyNotFoundError creates a new Error with NotFound type for a missing setup key
|
||||||
func NewSetupKeyNotFoundError(err error) error {
|
func NewSetupKeyNotFoundError(setupKeyID string) error {
|
||||||
return Errorf(NotFound, "setup key not found: %s", err)
|
return Errorf(NotFound, "setup key: %s not found", setupKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGetAccountFromStoreError(err error) error {
|
func NewGetAccountFromStoreError(err error) error {
|
||||||
return Errorf(Internal, "issue getting account from store: %s", err)
|
return Errorf(Internal, "issue getting account from store: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewUserNotPartOfAccountError creates a new Error with PermissionDenied type for a user not being part of an account
|
||||||
|
func NewUserNotPartOfAccountError() error {
|
||||||
|
return Errorf(PermissionDenied, "user is not part of this account")
|
||||||
|
}
|
||||||
|
|
||||||
// NewGetUserFromStoreError creates a new Error with Internal type for an issue getting user from store
|
// NewGetUserFromStoreError creates a new Error with Internal type for an issue getting user from store
|
||||||
func NewGetUserFromStoreError() error {
|
func NewGetUserFromStoreError() error {
|
||||||
return Errorf(Internal, "issue getting user from store")
|
return Errorf(Internal, "issue getting user from store")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdminPermissionError creates a new Error with PermissionDenied type for actions requiring admin role.
|
||||||
|
func NewAdminPermissionError() error {
|
||||||
|
return Errorf(PermissionDenied, "admin role required to perform this action")
|
||||||
|
}
|
||||||
|
|
||||||
// NewStoreContextCanceledError creates a new Error with Internal type for a canceled store context
|
// NewStoreContextCanceledError creates a new Error with Internal type for a canceled store context
|
||||||
func NewStoreContextCanceledError(duration time.Duration) error {
|
func NewStoreContextCanceledError(duration time.Duration) error {
|
||||||
return Errorf(Internal, "store access: context canceled after %v", duration)
|
return Errorf(Internal, "store access: context canceled after %v", duration)
|
||||||
@ -125,8 +135,3 @@ func NewStoreContextCanceledError(duration time.Duration) error {
|
|||||||
func NewInvalidKeyIDError() error {
|
func NewInvalidKeyIDError() error {
|
||||||
return Errorf(InvalidArgument, "invalid key ID")
|
return Errorf(InvalidArgument, "invalid key ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUnauthorizedToViewSetupKeysError creates a new Error with Unauthorized type for an issue getting a setup key
|
|
||||||
func NewUnauthorizedToViewSetupKeysError() error {
|
|
||||||
return Errorf(Unauthorized, "only users with admin power can view setup keys")
|
|
||||||
}
|
|
||||||
|
@ -70,9 +70,10 @@ type Store interface {
|
|||||||
DeleteHashedPAT2TokenIDIndex(hashedToken string) error
|
DeleteHashedPAT2TokenIDIndex(hashedToken string) error
|
||||||
DeleteTokenID2UserIDIndex(tokenID string) error
|
DeleteTokenID2UserIDIndex(tokenID string) error
|
||||||
|
|
||||||
GetAccountGroups(ctx context.Context, accountID string) ([]*nbgroup.Group, error)
|
GetAccountGroups(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*nbgroup.Group, error)
|
||||||
GetGroupByID(ctx context.Context, lockStrength LockingStrength, groupID, accountID string) (*nbgroup.Group, error)
|
GetGroupByID(ctx context.Context, lockStrength LockingStrength, groupID, accountID string) (*nbgroup.Group, error)
|
||||||
GetGroupByName(ctx context.Context, lockStrength LockingStrength, groupName, accountID string) (*nbgroup.Group, error)
|
GetGroupByName(ctx context.Context, lockStrength LockingStrength, groupName, accountID string) (*nbgroup.Group, error)
|
||||||
|
GetGroupsByIDs(ctx context.Context, lockStrength LockingStrength, accountID string, groupIDs []string) (map[string]*nbgroup.Group, error)
|
||||||
SaveGroups(ctx context.Context, lockStrength LockingStrength, groups []*nbgroup.Group) error
|
SaveGroups(ctx context.Context, lockStrength LockingStrength, groups []*nbgroup.Group) error
|
||||||
SaveGroup(ctx context.Context, lockStrength LockingStrength, group *nbgroup.Group) error
|
SaveGroup(ctx context.Context, lockStrength LockingStrength, group *nbgroup.Group) error
|
||||||
|
|
||||||
@ -96,7 +97,9 @@ type Store interface {
|
|||||||
GetSetupKeyBySecret(ctx context.Context, lockStrength LockingStrength, key string) (*SetupKey, error)
|
GetSetupKeyBySecret(ctx context.Context, lockStrength LockingStrength, key string) (*SetupKey, error)
|
||||||
IncrementSetupKeyUsage(ctx context.Context, setupKeyID string) error
|
IncrementSetupKeyUsage(ctx context.Context, setupKeyID string) error
|
||||||
GetAccountSetupKeys(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*SetupKey, error)
|
GetAccountSetupKeys(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*SetupKey, error)
|
||||||
GetSetupKeyByID(ctx context.Context, lockStrength LockingStrength, setupKeyID string, accountID string) (*SetupKey, error)
|
GetSetupKeyByID(ctx context.Context, lockStrength LockingStrength, accountID, setupKeyID string) (*SetupKey, error)
|
||||||
|
SaveSetupKey(ctx context.Context, lockStrength LockingStrength, setupKey *SetupKey) error
|
||||||
|
DeleteSetupKey(ctx context.Context, lockStrength LockingStrength, accountID, keyID string) error
|
||||||
|
|
||||||
GetAccountRoutes(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*route.Route, error)
|
GetAccountRoutes(ctx context.Context, lockStrength LockingStrength, accountID string) ([]*route.Route, error)
|
||||||
GetRouteByID(ctx context.Context, lockStrength LockingStrength, routeID string, accountID string) (*route.Route, error)
|
GetRouteByID(ctx context.Context, lockStrength LockingStrength, routeID string, accountID string) (*route.Route, error)
|
||||||
@ -124,7 +127,6 @@ type Store interface {
|
|||||||
// This is also a method of metrics.DataSource interface.
|
// This is also a method of metrics.DataSource interface.
|
||||||
GetStoreEngine() StoreEngine
|
GetStoreEngine() StoreEngine
|
||||||
ExecuteInTransaction(ctx context.Context, f func(store Store) error) error
|
ExecuteInTransaction(ctx context.Context, f func(store Store) error) error
|
||||||
DeleteSetupKey(ctx context.Context, accountID, keyID string) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoreEngine string
|
type StoreEngine string
|
||||||
|
@ -103,6 +103,11 @@ func (u *User) IsAdminOrServiceUser() bool {
|
|||||||
return u.HasAdminPower() || u.IsServiceUser
|
return u.HasAdminPower() || u.IsServiceUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRegularUser checks if the user is a regular user.
|
||||||
|
func (u *User) IsRegularUser() bool {
|
||||||
|
return !u.HasAdminPower() && !u.IsServiceUser
|
||||||
|
}
|
||||||
|
|
||||||
// ToUserInfo converts a User object to a UserInfo object.
|
// ToUserInfo converts a User object to a UserInfo object.
|
||||||
func (u *User) ToUserInfo(userData *idp.UserData, settings *Settings) (*UserInfo, error) {
|
func (u *User) ToUserInfo(userData *idp.UserData, settings *Settings) (*UserInfo, error) {
|
||||||
autoGroups := u.AutoGroups
|
autoGroups := u.AutoGroups
|
||||||
|
Loading…
Reference in New Issue
Block a user