mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-10 19:43:40 +00:00
260 lines
6.8 KiB
Go
260 lines
6.8 KiB
Go
package command
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/zitadel/zitadel/internal/domain"
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
type CreateSchemaUser struct {
|
|
ResourceOwner string
|
|
ID string
|
|
|
|
SchemaID string
|
|
Data json.RawMessage
|
|
|
|
Email *Email
|
|
ReturnCodeEmail *string
|
|
Phone *Phone
|
|
ReturnCodePhone *string
|
|
|
|
Usernames []*Username
|
|
Password *SchemaUserPassword
|
|
PublicKeys []*PublicKey
|
|
PATs []*PAT
|
|
}
|
|
|
|
func (s *CreateSchemaUser) Valid() (err error) {
|
|
if s.ResourceOwner == "" {
|
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-urEJKa1tJM", "Errors.ResourceOwnerMissing")
|
|
}
|
|
if s.SchemaID == "" {
|
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-TFo06JgnF2", "Errors.UserSchema.ID.Missing")
|
|
}
|
|
|
|
if s.Email != nil && s.Email.Address != "" {
|
|
if err := s.Email.Validate(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if s.Phone != nil && s.Phone.Number != "" {
|
|
if s.Phone.Number, err = s.Phone.Number.Normalize(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Commands) CreateSchemaUser(ctx context.Context, user *CreateSchemaUser) (_ *domain.ObjectDetails, err error) {
|
|
if err := user.Valid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if user.ID == "" {
|
|
user.ID, err = c.idGenerator.Next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
writeModel, err := c.getSchemaUserWMForState(ctx, user.ResourceOwner, user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
schemaWriteModel, err := existingSchema(ctx, c, "", user.SchemaID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
events, codeEmail, codePhone, err := writeModel.NewCreate(ctx,
|
|
schemaWriteModel,
|
|
user.Data,
|
|
user.Email,
|
|
user.Phone,
|
|
func(ctx context.Context) (*EncryptedCode, error) {
|
|
return c.newEmailCode(ctx, c.eventstore.Filter, c.userEncryption) //nolint:staticcheck
|
|
},
|
|
func(ctx context.Context) (*EncryptedCode, string, error) {
|
|
return c.newPhoneCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode, c.userEncryption, c.defaultSecretGenerators.PhoneVerificationCode) //nolint:staticcheck
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if codeEmail != "" {
|
|
user.ReturnCodeEmail = &codeEmail
|
|
}
|
|
if codePhone != "" {
|
|
user.ReturnCodePhone = &codePhone
|
|
}
|
|
for i := range user.Usernames {
|
|
_, usernameEvents, err := c.addUsername(ctx, writeModel.ResourceOwner, writeModel.AggregateID, user.Usernames[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
events = append(events, usernameEvents...)
|
|
}
|
|
if user.Password != nil {
|
|
_, pwEvents, err := c.setSchemaUserPassword(ctx, writeModel.ResourceOwner, writeModel.AggregateID, nil, user.Password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
events = append(events, pwEvents...)
|
|
}
|
|
for i := range user.PublicKeys {
|
|
_, pkEvents, err := c.addPublicKey(ctx, writeModel.ResourceOwner, writeModel.AggregateID, user.PublicKeys[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
events = append(events, pkEvents...)
|
|
}
|
|
for i := range user.PATs {
|
|
_, patEvents, err := c.addPAT(ctx, writeModel.ResourceOwner, writeModel.AggregateID, user.PATs[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
events = append(events, patEvents...)
|
|
}
|
|
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
|
|
}
|
|
|
|
func (c *Commands) DeleteSchemaUser(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
|
|
if id == "" {
|
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Vs4wJCME7T", "Errors.IDMissing")
|
|
}
|
|
writeModel, err := c.getSchemaUserWMForState(ctx, resourceOwner, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
events, err := writeModel.NewDelete(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
|
|
}
|
|
|
|
type ChangeSchemaUser struct {
|
|
schemaWriteModel *UserSchemaWriteModel
|
|
|
|
ResourceOwner string
|
|
ID string
|
|
|
|
SchemaUser *SchemaUser
|
|
|
|
Email *Email
|
|
ReturnCodeEmail *string
|
|
Phone *Phone
|
|
ReturnCodePhone *string
|
|
}
|
|
|
|
type SchemaUser struct {
|
|
SchemaID string
|
|
Data json.RawMessage
|
|
}
|
|
|
|
func (s *ChangeSchemaUser) Valid() (err error) {
|
|
if s.ID == "" {
|
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-gEJR1QOGHb", "Errors.IDMissing")
|
|
}
|
|
if s.Email != nil && s.Email.Address != "" {
|
|
if err := s.Email.Validate(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if s.Phone != nil && s.Phone.Number != "" {
|
|
if s.Phone.Number, err = s.Phone.Number.Normalize(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Commands) ChangeSchemaUser(ctx context.Context, user *ChangeSchemaUser) (*domain.ObjectDetails, error) {
|
|
if err := user.Valid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
writeModel, err := c.getSchemaUserWMByID(ctx, user.ResourceOwner, user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// use already used schemaID, if no new schemaID is defined
|
|
schemaID := writeModel.SchemaID
|
|
if user.SchemaUser != nil && user.SchemaUser.SchemaID != "" {
|
|
schemaID = user.SchemaUser.SchemaID
|
|
}
|
|
|
|
var schemaWM *UserSchemaWriteModel
|
|
if user.SchemaUser != nil {
|
|
schemaWriteModel, err := existingSchema(ctx, c, "", schemaID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
schemaWM = schemaWriteModel
|
|
}
|
|
|
|
events, codeEmail, codePhone, err := writeModel.NewUpdate(ctx,
|
|
schemaWM,
|
|
user.SchemaUser,
|
|
user.Email,
|
|
user.Phone,
|
|
func(ctx context.Context) (*EncryptedCode, error) {
|
|
return c.newEmailCode(ctx, c.eventstore.Filter, c.userEncryption) //nolint:staticcheck
|
|
},
|
|
func(ctx context.Context) (*EncryptedCode, string, error) {
|
|
return c.newPhoneCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode, c.userEncryption, c.defaultSecretGenerators.PhoneVerificationCode) //nolint:staticcheck
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if codeEmail != "" {
|
|
user.ReturnCodeEmail = &codeEmail
|
|
}
|
|
if codePhone != "" {
|
|
user.ReturnCodePhone = &codePhone
|
|
}
|
|
return c.pushAppendAndReduceDetails(ctx, writeModel, events...)
|
|
}
|
|
|
|
func (c *Commands) getSchemaUserWMByID(ctx context.Context, resourceOwner, id string) (*UserV3WriteModel, error) {
|
|
writeModel := NewUserV3WriteModel(resourceOwner, id, c.checkPermission)
|
|
if err := c.eventstore.FilterToQueryReducer(ctx, writeModel); err != nil {
|
|
return nil, err
|
|
}
|
|
return writeModel, nil
|
|
}
|
|
|
|
func existingSchema(ctx context.Context, c *Commands, resourceOwner, id string) (*UserSchemaWriteModel, error) {
|
|
writeModel, err := c.getSchemaWriteModelByID(ctx, resourceOwner, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !writeModel.Exists() {
|
|
return nil, zerrors.ThrowNotFound(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists")
|
|
}
|
|
return writeModel, nil
|
|
}
|
|
|
|
func existingSchemaWithAuthenticator(ctx context.Context, c *Commands, resourceOwner, id string, authenticator domain.AuthenticatorType) (*UserSchemaWriteModel, error) {
|
|
writeModel, err := c.getSchemaWriteModelByID(ctx, resourceOwner, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !writeModel.Exists() {
|
|
return nil, zerrors.ThrowNotFound(nil, "COMMAND-VLDTtxT3If", "Errors.UserSchema.NotExists")
|
|
}
|
|
return writeModel, nil
|
|
}
|