diff --git a/backend/internal/cmds/mgmt/serve/connect/cmd.go b/backend/internal/cmds/mgmt/serve/connect/cmd.go index 420cf2c354..67318b2e8c 100644 --- a/backend/internal/cmds/mgmt/serve/connect/cmd.go +++ b/backend/internal/cmds/mgmt/serve/connect/cmd.go @@ -548,10 +548,9 @@ func serve(ctx context.Context) error { db, tfwfmgr, connectionService, - useraccountService, sqlmanager, jobhookService, - rbacclient, + userdataclient, ) api.Handle( mgmtv1alpha1connect.NewJobServiceHandler( @@ -605,7 +604,7 @@ func serve(ctx context.Context) error { PresidioDefaultLanguage: getPresidioDefaultLanguage(), IsAuthEnabled: isAuthEnabled, IsNeosyncCloud: ncloudlicense.IsValid(), - }, anonymizerMeter, useraccountService, presAnalyzeClient, presAnonClient, db) + }, anonymizerMeter, userdataclient, useraccountService, presAnalyzeClient, presAnonClient, db) api.Handle( mgmtv1alpha1connect.NewAnonymizationServiceHandler( anonymizationService, diff --git a/backend/internal/ee/rbac/actions.go b/backend/internal/ee/rbac/actions.go index 0a92793b39..225d057050 100644 --- a/backend/internal/ee/rbac/actions.go +++ b/backend/internal/ee/rbac/actions.go @@ -13,6 +13,18 @@ func (a AccountAction) String() string { return string(a) } +type AccountMemberAction string + +const ( + AccountMemberAction_Invite AccountMemberAction = "invite" + AccountMemberAction_Delete AccountMemberAction = "delete" + AccountMemberAction_View AccountMemberAction = "view" +) + +func (a AccountMemberAction) String() string { + return string(a) +} + type ConnectionAction string const ( diff --git a/backend/internal/ee/rbac/policy.go b/backend/internal/ee/rbac/policy.go index 27461e82f1..10b018fa70 100644 --- a/backend/internal/ee/rbac/policy.go +++ b/backend/internal/ee/rbac/policy.go @@ -7,6 +7,7 @@ import ( "github.com/casbin/casbin/v2" mgmtv1alpha1 "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1" + nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" ) type Rbac struct { @@ -26,8 +27,11 @@ type Db interface { type EntityEnforcer interface { Job(ctx context.Context, user EntityString, account EntityString, job EntityString, action JobAction) (bool, error) + EnforceJob(ctx context.Context, user EntityString, account EntityString, job EntityString, action JobAction) error Connection(ctx context.Context, user EntityString, account EntityString, connection EntityString, action ConnectionAction) (bool, error) + EnforceConnection(ctx context.Context, user EntityString, account EntityString, connection EntityString, action ConnectionAction) error Account(ctx context.Context, user EntityString, account EntityString, action AccountAction) (bool, error) + EnforceAccount(ctx context.Context, user EntityString, account EntityString, action AccountAction) error } // Initialize default policies for existing accounts at startup @@ -145,6 +149,23 @@ func (r *Rbac) Job( return r.e.Enforce(user.String(), account.String(), job.String(), action.String()) } +func (r *Rbac) EnforceJob( + ctx context.Context, + user EntityString, + account EntityString, + job EntityString, + action JobAction, +) error { + ok, err := r.Job(ctx, user, account, job, action) + if err != nil { + return err + } + if !ok { + return nucleuserrors.NewForbidden(fmt.Sprintf("user does not have permission to %s job", action)) + } + return nil +} + func (r *Rbac) Connection( ctx context.Context, user EntityString, @@ -155,6 +176,23 @@ func (r *Rbac) Connection( return r.e.Enforce(user.String(), account.String(), connection.String(), action.String()) } +func (r *Rbac) EnforceConnection( + ctx context.Context, + user EntityString, + account EntityString, + connection EntityString, + action ConnectionAction, +) error { + ok, err := r.Connection(ctx, user, account, connection, action) + if err != nil { + return err + } + if !ok { + return nucleuserrors.NewForbidden(fmt.Sprintf("user does not have permission to %s connection", action)) + } + return nil +} + func (r *Rbac) Account( ctx context.Context, user EntityString, @@ -164,6 +202,22 @@ func (r *Rbac) Account( return r.e.Enforce(user.String(), account.String(), account.String(), action.String()) } +func (r *Rbac) EnforceAccount( + ctx context.Context, + user EntityString, + account EntityString, + action AccountAction, +) error { + ok, err := r.Account(ctx, user, account, action) + if err != nil { + return err + } + if !ok { + return nucleuserrors.NewForbidden(fmt.Sprintf("user does not have permission to %s account", action)) + } + return nil +} + func toRoleName(role mgmtv1alpha1.AccountRole) (string, error) { switch role { case mgmtv1alpha1.AccountRole_ACCOUNT_ROLE_ADMIN: diff --git a/backend/internal/userdata/user.go b/backend/internal/userdata/user.go index f81bcac19b..c0c6e95d4b 100644 --- a/backend/internal/userdata/user.go +++ b/backend/internal/userdata/user.go @@ -89,7 +89,7 @@ type UserEntityEnforcer struct { } type DomainEntity interface { - GetId() string + Identifier GetAccountId() string } type DomainEntityImpl struct { @@ -98,6 +98,10 @@ type DomainEntityImpl struct { isWild bool } +type Identifier interface { + GetId() string +} + func (j *DomainEntityImpl) GetId() string { return j.id } @@ -127,51 +131,37 @@ func NewDbDomainEntity(accountId, id pgtype.UUID) DomainEntity { } } -func (u *UserEntityEnforcer) Job(ctx context.Context, job DomainEntity, action rbac.JobAction) (bool, error) { - if err := u.enforceAccountAccess(ctx, job.GetAccountId()); err != nil { - return false, err +type IdentifierImpl struct { + id string +} + +func NewIdentifier(id string) Identifier { + return &IdentifierImpl{ + id: id, } - return u.enforcer.Job(ctx, u.user, rbac.NewAccountIdEntity(job.GetAccountId()), rbac.NewJobIdEntity(job.GetId()), action) } + +func (i *IdentifierImpl) GetId() string { + return i.id +} + func (u *UserEntityEnforcer) EnforceJob(ctx context.Context, job DomainEntity, action rbac.JobAction) error { - ok, err := u.Job(ctx, job, action) - if err != nil { + if err := u.enforceAccountAccess(ctx, job.GetAccountId()); err != nil { return err } - if !ok { - return nucleuserrors.NewForbidden(fmt.Sprintf("user does not have permission to %s job", action)) - } - return nil -} -func (u *UserEntityEnforcer) Connection(ctx context.Context, connection DomainEntity, action rbac.ConnectionAction) (bool, error) { - if err := u.enforceAccountAccess(ctx, connection.GetAccountId()); err != nil { - return false, err - } - return u.enforcer.Connection(ctx, u.user, rbac.NewAccountIdEntity(connection.GetAccountId()), rbac.NewConnectionIdEntity(connection.GetId()), action) + return u.enforcer.EnforceJob(ctx, u.user, rbac.NewAccountIdEntity(job.GetAccountId()), rbac.NewJobIdEntity(job.GetId()), action) } + func (u *UserEntityEnforcer) EnforceConnection(ctx context.Context, connection DomainEntity, action rbac.ConnectionAction) error { - ok, err := u.Connection(ctx, connection, action) - if err != nil { + if err := u.enforceAccountAccess(ctx, connection.GetAccountId()); err != nil { return err } - if !ok { - return nucleuserrors.NewForbidden(fmt.Sprintf("user does not have permission to %s connection", action)) - } - return nil + return u.enforcer.EnforceConnection(ctx, u.user, rbac.NewAccountIdEntity(connection.GetAccountId()), rbac.NewConnectionIdEntity(connection.GetId()), action) } -func (u *UserEntityEnforcer) Account(ctx context.Context, account *mgmtv1alpha1.UserAccount, action rbac.AccountAction) (bool, error) { + +func (u *UserEntityEnforcer) EnforceAccount(ctx context.Context, account Identifier, action rbac.AccountAction) error { if err := u.enforceAccountAccess(ctx, account.GetId()); err != nil { - return false, err - } - return u.enforcer.Account(ctx, u.user, rbac.NewAccountIdEntity(account.GetId()), action) -} -func (u *UserEntityEnforcer) EnforceAccount(ctx context.Context, account *mgmtv1alpha1.UserAccount, action rbac.AccountAction) error { - ok, err := u.Account(ctx, account, action) - if err != nil { return err } - if !ok { - return nucleuserrors.NewForbidden(fmt.Sprintf("user does not have permission to %s account", action)) - } - return nil + return u.enforcer.EnforceAccount(ctx, u.user, rbac.NewAccountIdEntity(account.GetId()), action) } diff --git a/backend/services/mgmt/v1alpha1/transformers-service/entities.go b/backend/services/mgmt/v1alpha1/transformers-service/entities.go index 8d17982b27..41f665d110 100644 --- a/backend/services/mgmt/v1alpha1/transformers-service/entities.go +++ b/backend/services/mgmt/v1alpha1/transformers-service/entities.go @@ -8,7 +8,9 @@ import ( "connectrpc.com/connect" mgmtv1alpha1 "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1" "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1/mgmtv1alpha1connect" + "github.com/nucleuscloud/neosync/backend/internal/ee/rbac" nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" + "github.com/nucleuscloud/neosync/backend/internal/userdata" presidioapi "github.com/nucleuscloud/neosync/internal/ee/presidio" ) @@ -26,7 +28,11 @@ func (s *Service) GetTransformPiiEntities( if s.entityclient == nil { return nil, nucleuserrors.NewInternalError("entity service is enabled but client was nil.") } - _, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + user, err := s.userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(req.Msg.GetAccountId()), rbac.JobAction_View) if err != nil { return nil, err } diff --git a/backend/services/mgmt/v1alpha1/transformers-service/service.go b/backend/services/mgmt/v1alpha1/transformers-service/service.go index 56e3aa144c..90156a070a 100644 --- a/backend/services/mgmt/v1alpha1/transformers-service/service.go +++ b/backend/services/mgmt/v1alpha1/transformers-service/service.go @@ -1,16 +1,16 @@ package v1alpha1_transformersservice import ( - "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1/mgmtv1alpha1connect" "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" + "github.com/nucleuscloud/neosync/backend/internal/userdata" presidioapi "github.com/nucleuscloud/neosync/internal/ee/presidio" ) type Service struct { - cfg *Config - db *neosyncdb.NeosyncDb - useraccountService mgmtv1alpha1connect.UserAccountServiceClient - entityclient presidioapi.EntityInterface + cfg *Config + db *neosyncdb.NeosyncDb + entityclient presidioapi.EntityInterface + userdataclient userdata.Client } type Config struct { @@ -21,13 +21,13 @@ type Config struct { func New( cfg *Config, db *neosyncdb.NeosyncDb, - useraccountService mgmtv1alpha1connect.UserAccountServiceClient, recognizerclient presidioapi.EntityInterface, + userdataclient userdata.Client, ) *Service { return &Service{ - cfg: cfg, - db: db, - useraccountService: useraccountService, - entityclient: recognizerclient, + cfg: cfg, + db: db, + entityclient: recognizerclient, + userdataclient: userdataclient, } } diff --git a/backend/services/mgmt/v1alpha1/transformers-service/user-account.go b/backend/services/mgmt/v1alpha1/transformers-service/user-account.go deleted file mode 100644 index 7b37ec17c9..0000000000 --- a/backend/services/mgmt/v1alpha1/transformers-service/user-account.go +++ /dev/null @@ -1,59 +0,0 @@ -package v1alpha1_transformersservice - -import ( - "context" - - "connectrpc.com/connect" - "github.com/jackc/pgx/v5/pgtype" - mgmtv1alpha1 "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1" - "github.com/nucleuscloud/neosync/backend/internal/apikey" - auth_apikey "github.com/nucleuscloud/neosync/backend/internal/auth/apikey" - nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" - "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" -) - -func (s *Service) verifyUserInAccount( - ctx context.Context, - accountId string, -) (*pgtype.UUID, error) { - accountUuid, err := neosyncdb.ToUuid(accountId) - if err != nil { - return nil, err - } - - if isWorkerApiKey(ctx) { - return &accountUuid, nil - } - - resp, err := s.useraccountService.IsUserInAccount(ctx, connect.NewRequest(&mgmtv1alpha1.IsUserInAccountRequest{AccountId: accountId})) - if err != nil { - return nil, err - } - if !resp.Msg.Ok { - return nil, nucleuserrors.NewForbidden("user in not in requested account") - } - - return &accountUuid, nil -} - -func (s *Service) getUserUuid( - ctx context.Context, -) (*pgtype.UUID, error) { - user, err := s.useraccountService.GetUser(ctx, connect.NewRequest(&mgmtv1alpha1.GetUserRequest{})) - if err != nil { - return nil, err - } - userUuid, err := neosyncdb.ToUuid(user.Msg.UserId) - if err != nil { - return nil, err - } - return &userUuid, nil -} - -func isWorkerApiKey(ctx context.Context) bool { - data, err := auth_apikey.GetTokenDataFromCtx(ctx) - if err != nil { - return false - } - return data.ApiKeyType == apikey.WorkerApiKey -} diff --git a/backend/services/mgmt/v1alpha1/transformers-service/userdefined_transformers.go b/backend/services/mgmt/v1alpha1/transformers-service/userdefined_transformers.go index 395e51094a..9159df007b 100644 --- a/backend/services/mgmt/v1alpha1/transformers-service/userdefined_transformers.go +++ b/backend/services/mgmt/v1alpha1/transformers-service/userdefined_transformers.go @@ -11,8 +11,10 @@ import ( mgmtv1alpha1 "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1" logger_interceptor "github.com/nucleuscloud/neosync/backend/internal/connect/interceptors/logger" "github.com/nucleuscloud/neosync/backend/internal/dtomaps" + "github.com/nucleuscloud/neosync/backend/internal/ee/rbac" nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" + "github.com/nucleuscloud/neosync/backend/internal/userdata" pg_models "github.com/nucleuscloud/neosync/backend/sql/postgresql/models" ) @@ -20,12 +22,20 @@ func (s *Service) GetUserDefinedTransformers( ctx context.Context, req *connect.Request[mgmtv1alpha1.GetUserDefinedTransformersRequest], ) (*connect.Response[mgmtv1alpha1.GetUserDefinedTransformersResponse], error) { - accountUuid, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + user, err := s.userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(req.Msg.GetAccountId()), rbac.JobAction_View) + if err != nil { + return nil, err + } + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } - transformers, err := s.db.Q.GetUserDefinedTransformersByAccount(ctx, s.db.Db, *accountUuid) + transformers, err := s.db.Q.GetUserDefinedTransformersByAccount(ctx, s.db.Db, accountUuid) if err != nil { return nil, err } @@ -49,7 +59,7 @@ func (s *Service) GetUserDefinedTransformerById( ctx context.Context, req *connect.Request[mgmtv1alpha1.GetUserDefinedTransformerByIdRequest], ) (*connect.Response[mgmtv1alpha1.GetUserDefinedTransformerByIdResponse], error) { - tId, err := neosyncdb.ToUuid(req.Msg.TransformerId) + tId, err := neosyncdb.ToUuid(req.Msg.GetTransformerId()) if err != nil { return nil, err } @@ -61,14 +71,18 @@ func (s *Service) GetUserDefinedTransformerById( return nil, nucleuserrors.NewNotFound("unable to find transformer by id") } - _, err = s.verifyUserInAccount(ctx, neosyncdb.UUIDString(transformer.AccountID)) + dto, err := dtomaps.ToUserDefinedTransformerDto(&transformer, s.getSystemTransformerSourceMap()) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to map user defined transformer %s with source %d: %w", neosyncdb.UUIDString(transformer.ID), transformer.Source, err) } - dto, err := dtomaps.ToUserDefinedTransformerDto(&transformer, s.getSystemTransformerSourceMap()) + user, err := s.userdataclient.GetUser(ctx) if err != nil { - return nil, fmt.Errorf("failed to map user defined transformer %s with source %d: %w", neosyncdb.UUIDString(transformer.ID), transformer.Source, err) + return nil, err + } + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(dto.GetAccountId()), rbac.JobAction_View) + if err != nil { + return nil, err } return connect.NewResponse(&mgmtv1alpha1.GetUserDefinedTransformerByIdResponse{ @@ -77,24 +91,27 @@ func (s *Service) GetUserDefinedTransformerById( } func (s *Service) CreateUserDefinedTransformer(ctx context.Context, req *connect.Request[mgmtv1alpha1.CreateUserDefinedTransformerRequest]) (*connect.Response[mgmtv1alpha1.CreateUserDefinedTransformerResponse], error) { - accountUuid, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + user, err := s.userdataclient.GetUser(ctx) if err != nil { return nil, err } - - userUuid, err := s.getUserUuid(ctx) + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(req.Msg.GetAccountId()), rbac.JobAction_Edit) + if err != nil { + return nil, err + } + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } UserDefinedTransformer := &db_queries.CreateUserDefinedTransformerParams{ - AccountID: *accountUuid, + AccountID: accountUuid, Name: req.Msg.Name, Description: req.Msg.Description, TransformerConfig: &pg_models.TransformerConfig{}, Source: int32(req.Msg.Source), - CreatedByID: *userUuid, - UpdatedByID: *userUuid, + CreatedByID: user.PgId(), + UpdatedByID: user.PgId(), } err = UserDefinedTransformer.TransformerConfig.FromTransformerConfigDto(req.Msg.TransformerConfig) @@ -119,9 +136,9 @@ func (s *Service) CreateUserDefinedTransformer(ctx context.Context, req *connect func (s *Service) DeleteUserDefinedTransformer(ctx context.Context, req *connect.Request[mgmtv1alpha1.DeleteUserDefinedTransformerRequest]) (*connect.Response[mgmtv1alpha1.DeleteUserDefinedTransformerResponse], error) { logger := logger_interceptor.GetLoggerFromContextOrDefault(ctx) - logger = logger.With("transformerId", req.Msg.TransformerId) + logger = logger.With("transformerId", req.Msg.GetTransformerId()) - tId, err := neosyncdb.ToUuid(req.Msg.TransformerId) + tId, err := neosyncdb.ToUuid(req.Msg.GetTransformerId()) if err != nil { return nil, err } @@ -133,7 +150,11 @@ func (s *Service) DeleteUserDefinedTransformer(ctx context.Context, req *connect return connect.NewResponse(&mgmtv1alpha1.DeleteUserDefinedTransformerResponse{}), nil } - _, err = s.verifyUserInAccount(ctx, neosyncdb.UUIDString(transformer.AccountID)) + user, err := s.userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(neosyncdb.UUIDString(transformer.AccountID)), rbac.JobAction_Delete) if err != nil { return nil, err } @@ -160,12 +181,11 @@ func (s *Service) UpdateUserDefinedTransformer(ctx context.Context, req *connect return nil, nucleuserrors.NewNotFound("unable to find transformer by id") } - _, err = s.verifyUserInAccount(ctx, neosyncdb.UUIDString(transformer.AccountID)) + user, err := s.userdataclient.GetUser(ctx) if err != nil { return nil, err } - - userUuid, err := s.getUserUuid(ctx) + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(neosyncdb.UUIDString(transformer.AccountID)), rbac.JobAction_Edit) if err != nil { return nil, err } @@ -174,11 +194,11 @@ func (s *Service) UpdateUserDefinedTransformer(ctx context.Context, req *connect Name: req.Msg.Name, Description: req.Msg.Description, TransformerConfig: &pg_models.TransformerConfig{}, - UpdatedByID: *userUuid, + UpdatedByID: user.PgId(), ID: tUuid, } // todo: must verify that this updated config is valid for the configured source - err = updateParams.TransformerConfig.FromTransformerConfigDto(req.Msg.TransformerConfig) + err = updateParams.TransformerConfig.FromTransformerConfigDto(req.Msg.GetTransformerConfig()) if err != nil { return nil, err } @@ -199,13 +219,21 @@ func (s *Service) UpdateUserDefinedTransformer(ctx context.Context, req *connect } func (s *Service) IsTransformerNameAvailable(ctx context.Context, req *connect.Request[mgmtv1alpha1.IsTransformerNameAvailableRequest]) (*connect.Response[mgmtv1alpha1.IsTransformerNameAvailableResponse], error) { - accountUuid, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + user, err := s.userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceJob(ctx, userdata.NewWildcardDomainEntity(req.Msg.GetAccountId()), rbac.JobAction_View) + if err != nil { + return nil, err + } + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } count, err := s.db.Q.IsTransformerNameAvailable(ctx, s.db.Db, db_queries.IsTransformerNameAvailableParams{ - AccountId: *accountUuid, + AccountId: accountUuid, TransformerName: req.Msg.TransformerName, }) if err != nil { diff --git a/backend/services/mgmt/v1alpha1/user-account-service/account-onboarding.go b/backend/services/mgmt/v1alpha1/user-account-service/account-onboarding.go index 2d59472c34..36d7720e94 100644 --- a/backend/services/mgmt/v1alpha1/user-account-service/account-onboarding.go +++ b/backend/services/mgmt/v1alpha1/user-account-service/account-onboarding.go @@ -6,6 +6,9 @@ import ( "connectrpc.com/connect" db_queries "github.com/nucleuscloud/neosync/backend/gen/go/db" mgmtv1alpha1 "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1" + "github.com/nucleuscloud/neosync/backend/internal/ee/rbac" + "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" + "github.com/nucleuscloud/neosync/backend/internal/userdata" pg_models "github.com/nucleuscloud/neosync/backend/sql/postgresql/models" ) @@ -13,12 +16,22 @@ func (s *Service) GetAccountOnboardingConfig( ctx context.Context, req *connect.Request[mgmtv1alpha1.GetAccountOnboardingConfigRequest], ) (*connect.Response[mgmtv1alpha1.GetAccountOnboardingConfigResponse], error) { - accountId, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_View) + if err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } - oc, err := s.db.Q.GetAccountOnboardingConfig(ctx, s.db.Db, *accountId) + oc, err := s.db.Q.GetAccountOnboardingConfig(ctx, s.db.Db, accountUuid) if err != nil { return nil, err } @@ -32,7 +45,17 @@ func (s *Service) SetAccountOnboardingConfig( ctx context.Context, req *connect.Request[mgmtv1alpha1.SetAccountOnboardingConfigRequest], ) (*connect.Response[mgmtv1alpha1.SetAccountOnboardingConfigResponse], error) { - accountId, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit) + if err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } @@ -47,7 +70,7 @@ func (s *Service) SetAccountOnboardingConfig( account, err := s.db.Q.UpdateAccountOnboardingConfig(ctx, s.db.Db, db_queries.UpdateAccountOnboardingConfigParams{ OnboardingConfig: onboardingConfigModel, - AccountId: *accountId, + AccountId: accountUuid, }) if err != nil { return nil, err diff --git a/backend/services/mgmt/v1alpha1/user-account-service/account-temporal-config.go b/backend/services/mgmt/v1alpha1/user-account-service/account-temporal-config.go index b2206d9d4e..8c50a81179 100644 --- a/backend/services/mgmt/v1alpha1/user-account-service/account-temporal-config.go +++ b/backend/services/mgmt/v1alpha1/user-account-service/account-temporal-config.go @@ -6,7 +6,10 @@ import ( "connectrpc.com/connect" db_queries "github.com/nucleuscloud/neosync/backend/gen/go/db" mgmtv1alpha1 "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1" + "github.com/nucleuscloud/neosync/backend/internal/ee/rbac" nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" + "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" + "github.com/nucleuscloud/neosync/backend/internal/userdata" pg_models "github.com/nucleuscloud/neosync/backend/sql/postgresql/models" ) @@ -17,7 +20,12 @@ func (s *Service) GetAccountTemporalConfig( if s.cfg.IsNeosyncCloud { return nil, nucleuserrors.NewNotImplemented("not enabled in Neosync Cloud") } - _, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_View) if err != nil { return nil, err } @@ -39,7 +47,18 @@ func (s *Service) SetAccountTemporalConfig( if s.cfg.IsNeosyncCloud { return nil, nucleuserrors.NewNotImplemented("not enabled in Neosync Cloud") } - accountUuid, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit) + if err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } @@ -54,7 +73,7 @@ func (s *Service) SetAccountTemporalConfig( _, err = s.db.Q.UpdateTemporalConfigByAccount(ctx, s.db.Db, db_queries.UpdateTemporalConfigByAccountParams{ TemporalConfig: tc, - AccountId: *accountUuid, + AccountId: accountUuid, }) if err != nil { return nil, err diff --git a/backend/services/mgmt/v1alpha1/user-account-service/billing.go b/backend/services/mgmt/v1alpha1/user-account-service/billing.go index 122bcf3465..0fe63dd5f2 100644 --- a/backend/services/mgmt/v1alpha1/user-account-service/billing.go +++ b/backend/services/mgmt/v1alpha1/user-account-service/billing.go @@ -14,8 +14,10 @@ import ( "github.com/nucleuscloud/neosync/backend/gen/go/protos/mgmt/v1alpha1/mgmtv1alpha1connect" logger_interceptor "github.com/nucleuscloud/neosync/backend/internal/connect/interceptors/logger" "github.com/nucleuscloud/neosync/backend/internal/dtomaps" + "github.com/nucleuscloud/neosync/backend/internal/ee/rbac" nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" + "github.com/nucleuscloud/neosync/backend/internal/userdata" "github.com/nucleuscloud/neosync/internal/billing" "github.com/stripe/stripe-go/v79" "google.golang.org/protobuf/types/known/timestamppb" @@ -32,16 +34,27 @@ func (s *Service) GetAccountStatus( ) (*connect.Response[mgmtv1alpha1.GetAccountStatusResponse], error) { logger := logger_interceptor.GetLoggerFromContextOrDefault(ctx) - accountId, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } - logger = logger.With("accountId", accountId) + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_View) + if err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) + if err != nil { + return nil, err + } + + logger = logger.With("accountId", req.Msg.GetAccountId()) if !s.cfg.IsNeosyncCloud || s.billingclient == nil { return connect.NewResponse(&mgmtv1alpha1.GetAccountStatusResponse{}), nil } - account, err := s.db.Q.GetAccount(ctx, s.db.Db, *accountId) + account, err := s.db.Q.GetAccount(ctx, s.db.Db, accountUuid) if err != nil { return nil, fmt.Errorf("unable to retrieve account: %w", err) } @@ -212,12 +225,21 @@ func (s *Service) GetAccountBillingCheckoutSession( return nil, nucleuserrors.NewNotImplemented(fmt.Sprintf("%s is not implemented", strings.TrimPrefix(mgmtv1alpha1connect.UserAccountServiceGetAccountBillingCheckoutSessionProcedure, "/"))) } logger = logger.With("accountId", req.Msg.GetAccountId()) - accountId, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } - user, err := s.GetUser(ctx, connect.NewRequest(&mgmtv1alpha1.GetUserRequest{})) + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) + if err != nil { + return nil, err + } + + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit) + if err != nil { + return nil, err + } if err != nil { return nil, err } @@ -225,8 +247,8 @@ func (s *Service) GetAccountBillingCheckoutSession( // retrieve the account, creates a customer id if one doesn't already exist account, err := s.db.UpsertStripeCustomerId( ctx, - *accountId, - s.getCreateStripeAccountFunction(user.Msg.GetUserId(), logger), + accountUuid, + s.getCreateStripeAccountFunction(user.Id(), logger), logger, ) if err != nil { @@ -236,7 +258,7 @@ func (s *Service) GetAccountBillingCheckoutSession( return nil, errors.New("stripe customer id does not exist on account after creation attempt") } - session, err := s.generateCheckoutSession(account.StripeCustomerID.String, account.AccountSlug, user.Msg.GetUserId(), logger) + session, err := s.generateCheckoutSession(account.StripeCustomerID.String, account.AccountSlug, user.Id(), logger) if err != nil { return nil, fmt.Errorf("unable to generate billing checkout session: %w", err) } @@ -253,12 +275,23 @@ func (s *Service) GetAccountBillingPortalSession( if !s.cfg.IsNeosyncCloud || s.billingclient == nil { return nil, nucleuserrors.NewNotImplemented(fmt.Sprintf("%s is not implemented", strings.TrimPrefix(mgmtv1alpha1connect.UserAccountServiceGetAccountBillingPortalSessionProcedure, "/"))) } - accountId, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } - account, err := s.db.Q.GetAccount(ctx, s.db.Db, *accountId) + err = user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit) + if err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) + if err != nil { + return nil, err + } + + account, err := s.db.Q.GetAccount(ctx, s.db.Db, accountUuid) if err != nil { return nil, err } @@ -279,7 +312,12 @@ func (s *Service) GetBillingAccounts( ctx context.Context, req *connect.Request[mgmtv1alpha1.GetBillingAccountsRequest], ) (*connect.Response[mgmtv1alpha1.GetBillingAccountsResponse], error) { - if s.cfg.IsNeosyncCloud && !isWorkerApiKey(ctx) { + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + if s.cfg.IsNeosyncCloud && !user.IsWorkerApiKey() { return nil, nucleuserrors.NewUnauthorized("must provide valid authentication credentials for this endpoint") } @@ -312,7 +350,12 @@ func (s *Service) SetBillingMeterEvent( if s.billingclient == nil { return nil, nucleuserrors.NewUnauthorized("billing is not currently enabled") } - if s.cfg.IsNeosyncCloud && !isWorkerApiKey(ctx) { + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + if s.cfg.IsNeosyncCloud && !user.IsWorkerApiKey() { return nil, nucleuserrors.NewUnauthorized("must provide valid authentication credentials for this endpoint") } diff --git a/backend/services/mgmt/v1alpha1/user-account-service/users.go b/backend/services/mgmt/v1alpha1/user-account-service/users.go index 6344fea248..a2b3c12a47 100644 --- a/backend/services/mgmt/v1alpha1/user-account-service/users.go +++ b/backend/services/mgmt/v1alpha1/user-account-service/users.go @@ -17,11 +17,12 @@ import ( "github.com/nucleuscloud/neosync/backend/internal/auth/tokenctx" logger_interceptor "github.com/nucleuscloud/neosync/backend/internal/connect/interceptors/logger" "github.com/nucleuscloud/neosync/backend/internal/dtomaps" + "github.com/nucleuscloud/neosync/backend/internal/ee/rbac" nucleuserrors "github.com/nucleuscloud/neosync/backend/internal/errors" "github.com/nucleuscloud/neosync/backend/internal/neosyncdb" + "github.com/nucleuscloud/neosync/backend/internal/userdata" "github.com/nucleuscloud/neosync/backend/internal/version" "github.com/nucleuscloud/neosync/internal/billing" - "github.com/nucleuscloud/neosync/internal/ee/rbac" "github.com/stripe/stripe-go/v79" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/types/known/timestamppb" @@ -64,6 +65,10 @@ func (s *Service) GetUser( return connect.NewResponse(&mgmtv1alpha1.GetUserResponse{ UserId: neosyncdb.UUIDString(tokenctxResp.ApiKeyContextData.ApiKey.UserID), }), nil + } else if tokenctxResp.ApiKeyContextData.ApiKeyType == apikey.WorkerApiKey { + return connect.NewResponse(&mgmtv1alpha1.GetUserResponse{ + UserId: "00000000-0000-0000-0000-000000000000", + }), nil } return nil, nucleuserrors.NewUnauthenticated(fmt.Sprintf("invalid api key type when calling GetUser: %s", tokenctxResp.ApiKeyContextData.ApiKeyType)) } else if tokenctxResp.JwtContextData != nil { @@ -137,7 +142,7 @@ func (s *Service) GetUserAccounts( if err != nil { return nil, err } - userId, err := neosyncdb.ToUuid(user.Msg.UserId) + userId, err := neosyncdb.ToUuid(user.Msg.GetUserId()) if err != nil { return nil, err } @@ -195,6 +200,28 @@ func (s *Service) ConvertPersonalToTeamAccount( break } } + } else { + personalAccountUuid, err := neosyncdb.ToUuid(personalAccountId) + if err != nil { + return nil, err + } + count, err := s.db.Q.IsUserInAccount(ctx, s.db.Db, db_queries.IsUserInAccountParams{ + AccountId: personalAccountUuid, + UserId: userId, + }) + if err != nil { + return nil, err + } + if count == 0 { + return nil, nucleuserrors.NewNotFound("user is not in the provided account") + } + account, err := s.db.Q.GetAccount(ctx, s.db.Db, personalAccountUuid) + if err != nil { + return nil, err + } + if account.AccountType != int16(neosyncdb.AccountType_Personal) { + return nil, nucleuserrors.NewNotFound("account is not a personal account") + } } personalAccountUuid, err := neosyncdb.ToUuid(personalAccountId) @@ -256,6 +283,8 @@ func (s *Service) SetPersonalAccount( return nil, err } + // todo: update rbac + return connect.NewResponse(&mgmtv1alpha1.SetPersonalAccountResponse{ AccountId: neosyncdb.UUIDString(account.ID), }), nil @@ -347,6 +376,8 @@ func (s *Service) CreateTeamAccount( checkoutSessionUrl = &session.URL } + // todo: set rbac role for user + return connect.NewResponse(&mgmtv1alpha1.CreateTeamAccountResponse{ AccountId: neosyncdb.UUIDString(account.ID), CheckoutSessionUrl: checkoutSessionUrl, @@ -402,16 +433,26 @@ func (s *Service) GetTeamAccountMembers( req *connect.Request[mgmtv1alpha1.GetTeamAccountMembersRequest], ) (*connect.Response[mgmtv1alpha1.GetTeamAccountMembersResponse], error) { logger := logger_interceptor.GetLoggerFromContextOrDefault(ctx) - accountId, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } + if err := user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_View); err != nil { + return nil, err + } - if err := s.verifyTeamAccount(ctx, *accountId); err != nil { + accountUuid, err := neosyncdb.ToUuid(req.Msg.AccountId) + if err != nil { return nil, err } - userIdentities, err := s.db.Q.GetUserIdentitiesByTeamAccount(ctx, s.db.Db, *accountId) + if err := s.verifyTeamAccount(ctx, accountUuid); err != nil { + return nil, err + } + + userIdentities, err := s.db.Q.GetUserIdentitiesByTeamAccount(ctx, s.db.Db, accountUuid) if err != nil { return nil, err } @@ -456,11 +497,21 @@ func (s *Service) RemoveTeamAccountMember( ctx context.Context, req *connect.Request[mgmtv1alpha1.RemoveTeamAccountMemberRequest], ) (*connect.Response[mgmtv1alpha1.RemoveTeamAccountMemberResponse], error) { - accountId, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + if err := user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit); err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } - if err := s.verifyTeamAccount(ctx, *accountId); err != nil { + + if err := s.verifyTeamAccount(ctx, accountUuid); err != nil { return nil, err } memberUserId, err := neosyncdb.ToUuid(req.Msg.UserId) @@ -468,7 +519,7 @@ func (s *Service) RemoveTeamAccountMember( return nil, err } err = s.db.Q.RemoveAccountUser(ctx, s.db.Db, db_queries.RemoveAccountUserParams{ - AccountId: *accountId, + AccountId: accountUuid, UserId: memberUserId, }) if err != nil && !neosyncdb.IsNoRows(err) { @@ -482,21 +533,21 @@ func (s *Service) InviteUserToTeamAccount( ctx context.Context, req *connect.Request[mgmtv1alpha1.InviteUserToTeamAccountRequest], ) (*connect.Response[mgmtv1alpha1.InviteUserToTeamAccountResponse], error) { - user, err := s.GetUser(ctx, connect.NewRequest(&mgmtv1alpha1.GetUserRequest{})) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } - userId, err := neosyncdb.ToUuid(user.Msg.UserId) - if err != nil { + if err := user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit); err != nil { return nil, err } - accountId, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } - if err := s.verifyTeamAccount(ctx, *accountId); err != nil { + if err := s.verifyTeamAccount(ctx, accountUuid); err != nil { return nil, err } @@ -506,7 +557,7 @@ func (s *Service) InviteUserToTeamAccount( return nil, err } - invite, err := s.db.CreateTeamAccountInvite(ctx, *accountId, userId, req.Msg.Email, expiresAt) + invite, err := s.db.CreateTeamAccountInvite(ctx, accountUuid, user.PgId(), req.Msg.GetEmail(), expiresAt) if err != nil { return nil, err } @@ -520,16 +571,25 @@ func (s *Service) GetTeamAccountInvites( ctx context.Context, req *connect.Request[mgmtv1alpha1.GetTeamAccountInvitesRequest], ) (*connect.Response[mgmtv1alpha1.GetTeamAccountInvitesResponse], error) { - accountId, err := s.verifyUserInAccount(ctx, req.Msg.AccountId) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) + if err != nil { + return nil, err + } + if err := user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_View); err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } - if err := s.verifyTeamAccount(ctx, *accountId); err != nil { + if err := s.verifyTeamAccount(ctx, accountUuid); err != nil { return nil, err } - invites, err := s.db.Q.GetActiveAccountInvites(ctx, s.db.Db, *accountId) + invites, err := s.db.Q.GetActiveAccountInvites(ctx, s.db.Db, accountUuid) if err != nil && !neosyncdb.IsNoRows(err) { return nil, nucleuserrors.New(err) } else if err != nil && neosyncdb.IsNoRows(err) { @@ -552,7 +612,7 @@ func (s *Service) RemoveTeamAccountInvite( ctx context.Context, req *connect.Request[mgmtv1alpha1.RemoveTeamAccountInviteRequest], ) (*connect.Response[mgmtv1alpha1.RemoveTeamAccountInviteResponse], error) { - inviteId, err := neosyncdb.ToUuid(req.Msg.Id) + inviteId, err := neosyncdb.ToUuid(req.Msg.GetId()) if err != nil { return nil, err } @@ -562,20 +622,23 @@ func (s *Service) RemoveTeamAccountInvite( } else if err != nil && neosyncdb.IsNoRows(err) { return connect.NewResponse(&mgmtv1alpha1.RemoveTeamAccountInviteResponse{}), nil } - accountId, err := s.verifyUserInAccount(ctx, neosyncdb.UUIDString(invite.AccountID)) + + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } + if err := user.EnforceAccount(ctx, userdata.NewIdentifier(neosyncdb.UUIDString(invite.AccountID)), rbac.AccountAction_Edit); err != nil { + return nil, err + } - if err := s.verifyTeamAccount(ctx, *accountId); err != nil { + if err := s.verifyTeamAccount(ctx, invite.AccountID); err != nil { return nil, err } err = s.db.Q.RemoveAccountInvite(ctx, s.db.Db, inviteId) if err != nil && !neosyncdb.IsNoRows(err) { return nil, nucleuserrors.New(err) - } else if err != nil && neosyncdb.IsNoRows(err) { - return connect.NewResponse(&mgmtv1alpha1.RemoveTeamAccountInviteResponse{}), nil } return connect.NewResponse(&mgmtv1alpha1.RemoveTeamAccountInviteResponse{}), nil @@ -643,12 +706,17 @@ func (s *Service) SetUserRole( ctx context.Context, req *connect.Request[mgmtv1alpha1.SetUserRoleRequest], ) (*connect.Response[mgmtv1alpha1.SetUserRoleResponse], error) { - user, err := s.GetUser(ctx, connect.NewRequest(&mgmtv1alpha1.GetUserRequest{})) + userdataclient := userdata.NewClient(s, s.rbacClient) + user, err := userdataclient.GetUser(ctx) if err != nil { return nil, err } - accountUuid, err := s.verifyUserInAccount(ctx, req.Msg.GetAccountId()) + if err := user.EnforceAccount(ctx, userdata.NewIdentifier(req.Msg.GetAccountId()), rbac.AccountAction_Edit); err != nil { + return nil, err + } + + accountUuid, err := neosyncdb.ToUuid(req.Msg.GetAccountId()) if err != nil { return nil, err } @@ -659,7 +727,7 @@ func (s *Service) SetUserRole( } count, err := s.db.Q.IsUserInAccount(ctx, s.db.Db, db_queries.IsUserInAccountParams{ - AccountId: *accountUuid, + AccountId: accountUuid, UserId: requestingUserUuid, }) if err != nil { @@ -669,19 +737,7 @@ func (s *Service) SetUserRole( return nil, nucleuserrors.NewBadRequest("provided user id is not in account") } - hasPerm, err := s.rbacClient.CanSetAccountRole( - ctx, - rbac.NewUserEntity(user.Msg.GetUserId()), - rbac.NewAccountIdEntity(req.Msg.GetAccountId()), - ) - if err != nil { - return nil, err - } - if !hasPerm { - return nil, nucleuserrors.NewForbidden("user does not have permission to set account roles") - } - - err = s.rbacClient.SetAccountRole(ctx, rbac.NewUserEntity(user.Msg.GetUserId()), rbac.NewAccountIdEntity(req.Msg.GetAccountId()), req.Msg.GetRole()) + err = s.rbacClient.SetAccountRole(ctx, rbac.NewPgUserIdEntity(requestingUserUuid), rbac.NewAccountIdEntity(req.Msg.GetAccountId()), req.Msg.GetRole()) if err != nil { return nil, err } @@ -694,42 +750,11 @@ func (s *Service) verifyTeamAccount(ctx context.Context, accountId pgtype.UUID) if err != nil { return err } - if account.AccountType != 1 { + if account.AccountType != int16(neosyncdb.AccountType_Team) && account.AccountType != int16(neosyncdb.AccountType_Enterprise) { return nucleuserrors.NewForbidden("account is not a team account") } return nil } -func isWorkerApiKey(ctx context.Context) bool { - data, err := auth_apikey.GetTokenDataFromCtx(ctx) - if err != nil { - return false - } - return data.ApiKeyType == apikey.WorkerApiKey -} - -func (s *Service) verifyUserInAccount( - ctx context.Context, - accountId string, -) (*pgtype.UUID, error) { - accountUuid, err := neosyncdb.ToUuid(accountId) - if err != nil { - return nil, err - } - - if isWorkerApiKey(ctx) { - return &accountUuid, nil - } - - resp, err := s.IsUserInAccount(ctx, connect.NewRequest(&mgmtv1alpha1.IsUserInAccountRequest{AccountId: accountId})) - if err != nil { - return nil, err - } - if !resp.Msg.Ok { - return nil, nucleuserrors.NewForbidden("user in not in requested account") - } - - return &accountUuid, nil -} func (s *Service) GetSystemInformation(ctx context.Context, req *connect.Request[mgmtv1alpha1.GetSystemInformationRequest]) (*connect.Response[mgmtv1alpha1.GetSystemInformationResponse], error) { versionInfo := version.Get()